aiobungie
A Pythonic async/await wrapper for interacting with the Bungie API.
Base client.
Example
import aiobungie
client = aiobungie.Client('YOUR_API_KEY')
# Search for Destiny2 users.
async def main() -> None:
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
print(f'{user.name} ({user.code})')
# Iterate through the users memberships.
for membership in user.memberships:
print(membership.type, membership.id)
client.run(main()) # or asyncio.run(main())
Single RESTClient instance.
The difference between base client and the REST clients:
- No Hight-Level concepts.
- All returned data are pure JSON objects from the API.
- No object creation.
Example
import aiobungie
async def main() -> None:
# Using `async with` context manager to close the session properly.
async with aiobungie.RESTClient("TOKEN") as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'], membership['iconPath'])
import asyncio
asyncio.run(main())
REST client pool.
A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.
Example
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def func1() -> None:
async with pool.acquire() as instance:
tokens = await instance.fetch_oauth2_tokens('code')
pool.metadata['tokens'] = tokens
# Other instance may access the tokens from pool since its shared.
async def func2() -> None:
async with pool.acquire() as instance:
tokens = pool.metadata['tokens']
tokens = await instance.refresh_access_token(tokens.refresh_token)
async def main() -> None:
await asyncio.gather(func1(), func2())
asyncio.run(main())
Should you use the base client or the REST client? This returns to you. For an example if you're building a website.
You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.
Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API. 24 25Base client. 26 27Example 28------- 29```py 30import aiobungie 31 32client = aiobungie.Client('YOUR_API_KEY') 33 34# Search for Destiny2 users. 35async def main() -> None: 36 users = await client.search_users('Crit') 37 38 # Iterate over the users and take the first 5 results. 39 for user in users.take(5): 40 print(f'{user.name} ({user.code})') 41 42 # Iterate through the users memberships. 43 for membership in user.memberships: 44 print(membership.type, membership.id) 45 46client.run(main()) # or asyncio.run(main()) 47``` 48 49Single RESTClient instance. 50 51The difference between base client and the REST clients: 52 53* No Hight-Level concepts. 54* All returned data are pure JSON objects from the API. 55* No object creation. 56 57Example 58------- 59```py 60import aiobungie 61 62async def main() -> None: 63 # Using `async with` context manager to close the session properly. 64 async with aiobungie.RESTClient("TOKEN") as rest: 65 payload = await rest.fetch_player('Fate怒', 4275) 66 67 for membership in payload: 68 print(membership['membershipId'], membership['iconPath']) 69 70import asyncio 71asyncio.run(main()) 72``` 73 74REST client pool. 75 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection. 77 78Example 79------- 80```py 81import aiobungie 82import asyncio 83 84pool = aiobungie.RESTPool("token") 85 86async def func1() -> None: 87 async with pool.acquire() as instance: 88 tokens = await instance.fetch_oauth2_tokens('code') 89 pool.metadata['tokens'] = tokens 90 91# Other instance may access the tokens from pool since its shared. 92 93async def func2() -> None: 94 async with pool.acquire() as instance: 95 tokens = pool.metadata['tokens'] 96 tokens = await instance.refresh_access_token(tokens.refresh_token) 97 98async def main() -> None: 99 await asyncio.gather(func1(), func2()) 100 101asyncio.run(main()) 102``` 103 104Should you use the base client or the REST client? 105This returns to you. For an example if you're building a website. 106 107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. 108Which gives you the freedom to deserialize it and implement your own logic in the front-end. 109 110Or of you're building a Discord bot for an example or something simple. The base client is the way to go. 111""" 112 113 114from __future__ import annotations 115 116from aiobungie import builders 117from aiobungie import crates 118from aiobungie import interfaces 119from aiobungie import traits 120from aiobungie import typedefs 121from aiobungie import url 122from aiobungie.client import Client 123from aiobungie.error import * 124from aiobungie.internal import iterators 125from aiobungie.internal.assets import Image 126from aiobungie.internal.enums import * 127from aiobungie.internal.factory import Factory 128from aiobungie.internal.iterators import * 129from aiobungie.rest import * 130from aiobungie.undefined import Undefined 131from aiobungie.undefined import UndefinedOr 132from aiobungie.undefined import UndefinedType 133 134from ._info import __about__ 135from ._info import __author__ 136from ._info import __docs__ 137from ._info import __email__ 138from ._info import __license__ 139from ._info import __url__ 140from ._info import __version__ 141 142# Alias for crate for backwards compatibility. 143crate = crates 144 145# Activity enums 146from .crates.activity import Difficulty 147 148# Components enums 149from .crates.components import ComponentFields 150from .crates.components import ComponentPrivacy 151 152# Entity enums 153from .crates.entity import GatingScope 154from .crates.entity import ObjectiveUIStyle 155from .crates.entity import ValueUIStyle 156 157# Fireteam enums. 158from .crates.fireteams import FireteamActivity 159from .crates.fireteams import FireteamDate 160from .crates.fireteams import FireteamLanguage 161from .crates.fireteams import FireteamPlatform 162 163# Records enums 164from .crates.records import RecordState 165 166__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
57@attrs.define(auto_exc=True) 58class AiobungieError(RuntimeError): 59 """Base exception class that all other errors inherit from."""
Base exception class that all other errors inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
646@typing.final 647class AmmoType(int, Enum): 648 """AN enum for Detyiny 2 ammo types.""" 649 650 NONE = 0 651 PRIMARY = 1 652 SPECIAL = 2 653 HEAVY = 3
AN enum for Detyiny 2 ammo types.
147@attrs.define(auto_exc=True) 148class BadRequest(HTTPError): 149 """Bad requests exceptions.""" 150 151 url: typing.Optional[typedefs.StrOrURL] 152 """The URL/endpoint caused this error.""" 153 154 body: typing.Any 155 """The response body.""" 156 157 headers: multidict.CIMultiDictProxy[str] 158 """The response headers.""" 159 160 http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)
Bad requests exceptions.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)
Method generated by attrs for class BadRequest.
701@typing.final 702class ClanMemberType(int, Enum): 703 """An enum for bungie clan member types.""" 704 705 NONE = 0 706 BEGINNER = 1 707 MEMBER = 2 708 ADMIN = 3 709 ACTING_FOUNDER = 4 710 FOUNDER = 5
An enum for bungie clan member types.
477@typing.final 478class Class(int, Enum): 479 """An Enum for Destiny character classes.""" 480 481 TITAN = 0 482 HUNTER = 1 483 WARLOCK = 2 484 UNKNOWN = 3
An Enum for Destiny character classes.
61class Client(traits.ClientApp): 62 """Standard Bungie API client application. 63 64 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 65 and returns `aiobungie.crates` Python object implementations of the responses. 66 67 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 68 69 Example 70 ------- 71 ```py 72 import aiobungie 73 74 client = aiobungie.Client('...') 75 76 async def main(): 77 async with client.rest: 78 user = await client.fetch_current_user_memberships('...') 79 print(user) 80 ``` 81 82 Parameters 83 ----------- 84 token: `str` 85 Your Bungie's API key or Token from the developer's portal. 86 87 Other Parameters 88 ---------------- 89 rest_client: `aiobungie.interfaces.RESTInterface | None` 90 An optional rest client instance you can pass. 91 If set to `None` then the client will use the default instance. 92 93 max_retries : `int` 94 The max retries number to retry if the request hit a `5xx` status code. 95 max_ratelimit_retries : `int` 96 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 97 client_secret : `str | None` 98 An optional application client secret, 99 This is only needed if you're fetching OAuth2 tokens with this client. 100 client_id : `int | None` 101 An optional application client id, 102 This is only needed if you're fetching OAuth2 tokens with this client. 103 """ 104 105 __slots__ = ("_rest", "_factory", "_client_secret", "_client_id") 106 107 def __init__( 108 self, 109 token: str, 110 /, 111 client_secret: typing.Optional[str] = None, 112 client_id: typing.Optional[int] = None, 113 *, 114 rest_client: typing.Optional[interfaces.RESTInterface] = None, 115 max_retries: int = 4, 116 max_ratelimit_retries: int = 3, 117 ) -> None: 118 119 self._client_secret = client_secret 120 self._client_id = client_id 121 122 self._rest = ( 123 rest_client 124 if rest_client is not None 125 else rest_.RESTClient( 126 token, 127 client_secret, 128 client_id, 129 max_retries=max_retries, 130 max_ratelimit_retries=max_ratelimit_retries, 131 ) 132 ) 133 134 self._factory = factory_.Factory(self) 135 136 @property 137 def factory(self) -> factory_.Factory: 138 return self._factory 139 140 @property 141 def rest(self) -> interfaces.RESTInterface: 142 return self._rest 143 144 @property 145 def request(self) -> Client: 146 return copy.copy(self) 147 148 @property 149 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 150 return self._rest.metadata 151 152 def run( 153 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 154 ) -> None: 155 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 156 try: 157 if not loop.is_running(): 158 loop.set_debug(debug) 159 loop.run_until_complete(future) 160 161 except Exception as exc: 162 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 163 164 except KeyboardInterrupt: 165 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 166 return 167 168 # * User methods. 169 170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp) 189 190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload) 215 216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 ) 239 240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data) 251 252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 ) 283 284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload) 319 320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp) 348 349 # * Destiny 2. 350 351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data) 389 390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp) 429 430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp) 462 463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp) 503 504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ] 534 535 # * Destiny 2 Activities. 536 537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp) 589 590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp) 606 607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp) 639 640 # * Destiny 2 Clans or GroupsV2. 641 642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp) 668 669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp) 709 710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp) 727 728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp) 751 752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ] 790 791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ] 829 830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp) 868 869 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 870 """Fetch the clan banners. 871 872 Returns 873 ------- 874 `collections.Sequence[aiobungie.crates.ClanBanner]` 875 A sequence of the clan banners. 876 """ 877 resp = await self.rest.fetch_clan_banners() 878 879 return self.factory.deserialize_clan_banners(resp) 880 881 # This method is required to be here since it deserialize the clan. 882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp) 919 920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp) 937 938 # * Destiny 2 Entities aka Definitions. 939 940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp) 956 957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp) 973 974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp) 1000 1001 # Fireteams 1002 1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp) 1055 1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp) 1119 1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value] 1147 1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1203 1204 # Friends and social. 1205 1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp) 1228 1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp) 1251 1252 # Applications and Developer portal. 1253 1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp) 1270 1271 # Milestones 1272 1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using aiobungie.Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Example
import aiobungie
client = aiobungie.Client('...')
async def main():
async with client.rest:
user = await client.fetch_current_user_memberships('...')
print(user)
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- rest_client (
aiobungie.interfaces.RESTInterface | None): An optional rest client instance you can pass. If set toNonethen the client will use the default instance. - max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
107 def __init__( 108 self, 109 token: str, 110 /, 111 client_secret: typing.Optional[str] = None, 112 client_id: typing.Optional[int] = None, 113 *, 114 rest_client: typing.Optional[interfaces.RESTInterface] = None, 115 max_retries: int = 4, 116 max_ratelimit_retries: int = 3, 117 ) -> None: 118 119 self._client_secret = client_secret 120 self._client_id = client_id 121 122 self._rest = ( 123 rest_client 124 if rest_client is not None 125 else rest_.RESTClient( 126 token, 127 client_secret, 128 client_id, 129 max_retries=max_retries, 130 max_ratelimit_retries=max_ratelimit_retries, 131 ) 132 ) 133 134 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
152 def run( 153 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 154 ) -> None: 155 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 156 try: 157 if not loop.is_running(): 158 loop.set_debug(debug) 159 loop.run_until_complete(future) 160 161 except Exception as exc: 162 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 163 164 except KeyboardInterrupt: 165 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 166 return
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
aiobungie.NotFound: The user was not found.
216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
aiobungie.MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
aiobungie.MembershipType): The Member ship type.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
782@typing.final 783class ClosedReasons(Flag): 784 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 785 786 NONE = 0 787 MATCHMAKING = 1 788 LOADING = 2 789 SOLO = 4 790 """The activity is required to be played solo.""" 791 INTERNAL_REASONS = 8 792 """ 793 The user can't be joined for one of a variety of internal reasons. 794 Basically, the game can't let you join at this time, 795 but for reasons that aren't under the control of this user 796 """ 797 DISALLOWED_BY_GAME_STATE = 16 798 """The user's current activity/quest/other transitory game state is preventing joining.""" 799 OFFLINE = 32768 800 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
363@typing.final 364class ComponentType(Enum): 365 """An Enum for Destiny 2 profile Components.""" 366 367 NONE = 0 368 369 PROFILE = 100 370 PROFILE_INVENTORIES = 102 371 PROFILE_CURRENCIES = 103 372 PROFILE_PROGRESSION = 104 373 ALL_PROFILES = ( 374 PROFILE, 375 PROFILE_INVENTORIES, 376 PROFILE_CURRENCIES, 377 PROFILE_PROGRESSION, 378 ) 379 """All profile components.""" 380 381 VENDORS = 400 382 VENDOR_SALES = 402 383 VENDOR_RECEIPTS = 101 384 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 385 """All vendor components.""" 386 387 # Items 388 ITEM_INSTANCES = 300 389 ITEM_OBJECTIVES = 301 390 ITEM_PERKS = 302 391 ITEM_RENDER_DATA = 303 392 ITEM_STATS = 304 393 ITEM_SOCKETS = 305 394 ITEM_TALENT_GRINDS = 306 395 ITEM_PLUG_STATES = 308 396 ITEM_PLUG_OBJECTIVES = 309 397 ITEM_REUSABLE_PLUGS = 310 398 399 ALL_ITEMS = ( 400 ITEM_PLUG_OBJECTIVES, 401 ITEM_PLUG_STATES, 402 ITEM_SOCKETS, 403 ITEM_INSTANCES, 404 ITEM_OBJECTIVES, 405 ITEM_PERKS, 406 ITEM_RENDER_DATA, 407 ITEM_STATS, 408 ITEM_TALENT_GRINDS, 409 ITEM_REUSABLE_PLUGS, 410 ) 411 """All item components.""" 412 413 PLATFORM_SILVER = 105 414 KIOSKS = 500 415 CURRENCY_LOOKUPS = 600 416 PRESENTATION_NODES = 700 417 COLLECTIBLES = 800 418 RECORDS = 900 419 TRANSITORY = 1000 420 METRICS = 1100 421 INVENTORIES = 102 422 STRING_VARIABLES = 1200 423 CRAFTABLES = 1300 424 425 CHARACTERS = 200 426 CHARACTER_INVENTORY = 201 427 CHARECTER_PROGRESSION = 202 428 CHARACTER_RENDER_DATA = 203 429 CHARACTER_ACTIVITIES = 204 430 CHARACTER_EQUIPMENT = 205 431 432 ALL_CHARACTERS = ( 433 CHARACTERS, 434 CHARACTER_INVENTORY, 435 CHARECTER_PROGRESSION, 436 CHARACTER_RENDER_DATA, 437 CHARACTER_ACTIVITIES, 438 CHARACTER_EQUIPMENT, 439 RECORDS, 440 ) 441 """All character components.""" 442 443 ALL = ( 444 *ALL_PROFILES, # type: ignore 445 *ALL_CHARACTERS, # type: ignore 446 *ALL_VENDORS, # type: ignore 447 *ALL_ITEMS, # type: ignore 448 RECORDS, 449 CURRENCY_LOOKUPS, 450 PRESENTATION_NODES, 451 COLLECTIBLES, 452 KIOSKS, 453 METRICS, 454 PLATFORM_SILVER, 455 INVENTORIES, 456 STRING_VARIABLES, 457 TRANSITORY, 458 CRAFTABLES, 459 ) 460 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
664@typing.final 665class CredentialType(int, Enum): 666 """The types of the accounts system supports at bungie.""" 667 668 NONE = 0 669 XUID = 1 670 PSNID = 2 671 WILD = 3 672 FAKE = 4 673 FACEBOOK = 5 674 GOOGLE = 8 675 WINDOWS = 9 676 DEMONID = 10 677 STEAMID = 12 678 BATTLENETID = 14 679 STADIAID = 16 680 TWITCHID = 18
The types of the accounts system supports at bungie.
542@typing.final 543class DamageType(int, Enum): 544 """Enums for Destiny Damage types""" 545 546 NONE = 0 547 KINETIC = 1 548 ARC = 2 549 SOLAR = 3 550 VOID = 4 551 RAID = 5 552 """This is a special damage type reserved for some raid activity encounters.""" 553 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
65@typing.final 66class Difficulty(int, enums.Enum): 67 """An enum for activities difficulties.""" 68 69 TRIVIAL = 0 70 EASY = 1 71 NORMAL = 2 72 CHALLENGING = 3 73 HARD = 4 74 BRAVE = 5 75 ALMOST_IMPOSSIBLE = 6 76 IMPOSSIBLE = 7
An enum for activities difficulties.
165@typing.final 166class Dungeon(int, Enum): 167 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 168 169 NORMAL_PRESAGE = 2124066889 170 """Normal Presage""" 171 172 MASTER_PRESAGE = 4212753278 173 """Master Presage""" 174 175 HARBINGER = 1738383283 176 """Harbinger""" 177 178 PROPHECY = 4148187374 179 """Prophecy""" 180 181 MASTER_POH = 785700673 182 """Master Pit of Heresy?""" 183 184 LEGEND_POH = 785700678 185 """Legend Pit of Heresy?""" 186 187 POH = 1375089621 188 """Normal Pit of Heresy.""" 189 190 SHATTERED = 2032534090 191 """Shattered Throne""" 192 193 GOA_LEGEND = 4078656646 194 """Grasp of Avarice legend.""" 195 196 GOA_MASTER = 3774021532 197 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
77class Enum(__enum.Enum): 78 """Builtin Python enum with extra handlings.""" 79 80 @property 81 def name(self) -> str: # type: ignore[override] 82 return self._name_ 83 84 @property 85 def value(self) -> typing.Any: # type: ignore[override] 86 return self._value_ 87 88 def __str__(self) -> str: 89 return self._name_ 90 91 def __repr__(self) -> str: 92 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 93 94 def __int__(self) -> int: 95 if isinstance(self.value, _ITERABLE): 96 raise TypeError( 97 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 98 ) 99 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 ) 140 141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data] 145 146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 ) 157 158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 ) 183 184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ] 196 197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ] 213 214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload)) 218 219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 ) 297 298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 ) 320 321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 ) 327 328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 ) 343 344 def _deserialize_clan_conversation( 345 self, payload: typedefs.JSONObject 346 ) -> clans.ClanConversation: 347 return clans.ClanConversation( 348 net=self._net, 349 id=int(payload["conversationId"]), 350 group_id=int(payload["groupId"]), 351 name=( 352 payload["chatName"] 353 if not typedefs.is_unknown(payload["chatName"]) 354 else undefined.Undefined 355 ), 356 chat_enabled=payload["chatEnabled"], 357 security=payload["chatSecurity"], 358 ) 359 360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload] 364 365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 ) 377 378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 ) 390 391 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 392 total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True) 393 return character.Character( 394 net=self._net, 395 id=int(payload["characterId"]), 396 gender=enums.Gender(payload["genderType"]), 397 race=enums.Race(payload["raceType"]), 398 class_type=enums.Class(payload["classType"]), 399 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 400 emblem_icon=assets.Image(str(payload["emblemPath"])), 401 emblem_hash=int(payload["emblemHash"]), 402 last_played=time.clean_date(payload["dateLastPlayed"]), 403 total_played_time=total_time, 404 member_id=int(payload["membershipId"]), 405 member_type=enums.MembershipType(payload["membershipType"]), 406 level=payload["baseCharacterLevel"], 407 title_hash=payload.get("titleRecordHash", None), 408 light=payload["light"], 409 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 410 ) 411 412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 ) 437 438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 ) 468 469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 ) 480 481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 ) 512 513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 ) 533 534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 ) 538 539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 ) 556 557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 ) 567 568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 ) 586 587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 ) 601 602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 ) 627 628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]] 632 633 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 634 return records.Node( 635 state=int(payload["state"]), 636 objective=self.deserialize_objectives(payload["objective"]) 637 if "objective" in payload 638 else None, 639 progress_value=int(payload["progressValue"]), 640 completion_value=int(payload["completionValue"]), 641 record_category_score=int(payload["recordCategoryScore"]) 642 if "recordCategoryScore" in payload 643 else None, 644 ) 645 646 @staticmethod 647 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 648 recent_collectibles: typing.Optional[collections.Collection[int]] = None 649 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 650 recent_collectibles = [ 651 int(item_hash) for item_hash in raw_recent_collectibles 652 ] 653 654 collectibles: dict[int, int] = {} 655 for item_hash, mapping in payload["collectibles"].items(): 656 collectibles[int(item_hash)] = int(mapping["state"]) 657 658 return items.Collectible( 659 recent_collectibles=recent_collectibles, 660 collectibles=collectibles, 661 collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]), 662 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 663 ) 664 665 @staticmethod 666 def _deserialize_currencies( 667 payload: typedefs.JSONObject, 668 ) -> collections.Sequence[items.Currency]: 669 return [ 670 items.Currency(hash=int(item_hash), amount=int(amount)) 671 for item_hash, amount in payload["itemQuantities"].items() 672 ] 673 674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 ) 688 689 def _deserialize_factions( 690 self, payload: typedefs.JSONObject 691 ) -> progressions.Factions: 692 progs = self.deserialize_progressions(payload) 693 return progressions.Factions( 694 hash=progs.hash, 695 level=progs.level, 696 cap=progs.cap, 697 daily_limit=progs.daily_limit, 698 weekly_limit=progs.weekly_limit, 699 current_progress=progs.current_progress, 700 daily_progress=progs.daily_progress, 701 needed=progs.needed, 702 next_level=progs.next_level, 703 faction_hash=payload["factionHash"], 704 faction_vendor_hash=payload["factionVendorIndex"], 705 ) 706 707 def _deserialize_milestone_available_quest( 708 self, payload: typedefs.JSONObject 709 ) -> milestones.MilestoneQuest: 710 return milestones.MilestoneQuest( 711 item_hash=payload["questItemHash"], 712 status=self._deserialize_milestone_quest_status(payload["status"]), 713 ) 714 715 def _deserialize_milestone_activity( 716 self, payload: typedefs.JSONObject 717 ) -> milestones.MilestoneActivity: 718 719 phases: typing.Optional[ 720 collections.Sequence[milestones.MilestoneActivityPhase] 721 ] = None 722 if raw_phases := payload.get("phases"): 723 phases = [ 724 milestones.MilestoneActivityPhase( 725 is_completed=obj["complete"], hash=obj["phaseHash"] 726 ) 727 for obj in raw_phases 728 ] 729 730 return milestones.MilestoneActivity( 731 hash=payload["activityHash"], 732 challenges=[ 733 self.deserialize_objectives(obj["objective"]) 734 for obj in payload["challenges"] 735 ], 736 modifier_hashes=payload.get("modifierHashes"), 737 boolean_options=payload.get("booleanActivityOptions"), 738 phases=phases, 739 ) 740 741 def _deserialize_milestone_quest_status( 742 self, payload: typedefs.JSONObject 743 ) -> milestones.QuestStatus: 744 return milestones.QuestStatus( 745 net=self._net, 746 quest_hash=payload["questHash"], 747 step_hash=payload["stepHash"], 748 step_objectives=[ 749 self.deserialize_objectives(objective) 750 for objective in payload["stepObjectives"] 751 ], 752 is_tracked=payload["tracked"], 753 is_completed=payload["completed"], 754 started=payload["started"], 755 item_instance_id=payload["itemInstanceId"], 756 vendor_hash=payload.get("vendorHash"), 757 is_redeemed=payload["redeemed"], 758 ) 759 760 def _deserialize_milestone_rewards( 761 self, payload: typedefs.JSONObject 762 ) -> milestones.MilestoneReward: 763 return milestones.MilestoneReward( 764 category_hash=payload["rewardCategoryHash"], 765 entries=[ 766 milestones.MilestoneRewardEntry( 767 entry_hash=entry["rewardEntryHash"], 768 is_earned=entry["earned"], 769 is_redeemed=entry["redeemed"], 770 ) 771 for entry in payload["entries"] 772 ], 773 ) 774 775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 ) 832 833 def _deserialize_artifact_tiers( 834 self, payload: typedefs.JSONObject 835 ) -> season.ArtifactTier: 836 return season.ArtifactTier( 837 hash=payload["tierHash"], 838 is_unlocked=payload["isUnlocked"], 839 points_to_unlock=payload["pointsToUnlock"], 840 items=[ 841 season.ArtifactTierItem( 842 hash=item["itemHash"], is_active=item["isActive"] 843 ) 844 for item in payload["items"] 845 ], 846 ) 847 848 def deserialize_characters( 849 self, payload: typedefs.JSONObject 850 ) -> collections.Mapping[int, character.Character]: 851 return { 852 int(char_id): self._set_character_attrs(char) 853 for char_id, char in payload["data"].items() 854 } 855 856 def deserialize_character( 857 self, payload: typedefs.JSONObject 858 ) -> character.Character: 859 return self._set_character_attrs(payload) 860 861 def deserialize_character_equipments( 862 self, payload: typedefs.JSONObject 863 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 864 return { 865 int(char_id): self.deserialize_profile_items(item) 866 for char_id, item in payload["data"].items() 867 } 868 869 def deserialize_character_activities( 870 self, payload: typedefs.JSONObject 871 ) -> collections.Mapping[int, activity.CharacterActivity]: 872 return { 873 int(char_id): self.deserialize_character_activity(data) 874 for char_id, data in payload["data"].items() 875 } 876 877 def deserialize_characters_render_data( 878 self, payload: typedefs.JSONObject 879 ) -> collections.Mapping[int, character.RenderedData]: 880 return { 881 int(char_id): self.deserialize_character_render_data(data) 882 for char_id, data in payload["data"].items() 883 } 884 885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 ) 927 928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions 938 939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 } 950 951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 } 969 970 def _deserialize_craftable_socket_plug( 971 self, payload: typedefs.JSONObject 972 ) -> items.CraftableSocketPlug: 973 return items.CraftableSocketPlug( 974 item_hash=int(payload["plugItemHash"]), 975 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 976 ) 977 978 def _deserialize_craftable_socket( 979 self, payload: typedefs.JSONObject 980 ) -> items.CraftableSocket: 981 982 plugs: list[items.CraftableSocketPlug] = [] 983 if raw_plug := payload.get("plug"): 984 plugs.extend( 985 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 986 ) 987 988 return items.CraftableSocket( 989 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 990 ) 991 992 def _deserialize_craftable_item( 993 self, payload: typedefs.JSONObject 994 ) -> items.CraftableItem: 995 996 return items.CraftableItem( 997 is_visible=payload["visible"], 998 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 999 sockets=[ 1000 self._deserialize_craftable_socket(socket) 1001 for socket in payload["sockets"] 1002 ], 1003 ) 1004 1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 ) 1017 1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 ) 1285 1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 ) 1393 1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 ) 1469 1470 def _set_entity_attrs( 1471 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1472 ) -> entity.Entity: 1473 1474 name: undefined.UndefinedOr[str] = undefined.Undefined 1475 description: undefined.UndefinedOr[str] = undefined.Undefined 1476 1477 if properties := payload[key]: 1478 if (raw_name := properties["name"]) is not typedefs.Unknown: 1479 name = raw_name 1480 1481 if ( 1482 raw_description := properties["description"] 1483 ) and not typedefs.is_unknown(raw_description): 1484 description = raw_description 1485 1486 return entity.Entity( 1487 net=self._net, 1488 hash=payload["hash"], 1489 index=payload["index"], 1490 name=name, 1491 description=description, 1492 has_icon=properties["hasIcon"], 1493 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1494 ) 1495 1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 ) 1522 1523 def _deserialize_inventory_item_objects( 1524 self, payload: typedefs.JSONObject 1525 ) -> entity.InventoryEntityObjects: 1526 return entity.InventoryEntityObjects( 1527 action=payload.get("action"), 1528 set_data=payload.get("setData"), 1529 stats=payload.get("stats"), 1530 equipping_block=payload.get("equippingBlock"), 1531 translation_block=payload.get("translationBlock"), 1532 preview=payload.get("preview"), 1533 quality=payload.get("quality"), 1534 value=payload.get("value"), 1535 source_data=payload.get("sourceData"), 1536 objectives=payload.get("objectives"), 1537 plug=payload.get("plug"), 1538 metrics=payload.get("metrics"), 1539 gearset=payload.get("gearset"), 1540 sack=payload.get("sack"), 1541 sockets=payload.get("sockets"), 1542 summary=payload.get("summary"), 1543 talent_gird=payload.get("talentGrid"), 1544 investments_stats=payload.get("investmentStats"), 1545 perks=payload.get("perks"), 1546 animations=payload.get("animations", []), 1547 links=payload.get("links", []), 1548 ) 1549 1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 ) 1725 1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 ) 1762 1763 def _deserialize_activity_values( 1764 self, payload: typedefs.JSONObject, / 1765 ) -> activity.ActivityValues: 1766 team: typing.Optional[int] = None 1767 if raw_team := payload.get("team"): 1768 team = raw_team["basic"]["value"] 1769 return activity.ActivityValues( 1770 assists=payload["assists"]["basic"]["value"], 1771 deaths=payload["deaths"]["basic"]["value"], 1772 kills=payload["kills"]["basic"]["value"], 1773 is_completed=bool(payload["completed"]["basic"]["value"]), 1774 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1775 efficiency=payload["efficiency"]["basic"]["value"], 1776 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1777 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1778 score=payload["score"]["basic"]["value"], 1779 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1780 team=team, 1781 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1782 fireteam_id=payload["fireteamId"]["basic"]["value"], 1783 start_seconds=payload["startSeconds"]["basic"]["value"], 1784 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1785 player_count=payload["playerCount"]["basic"]["value"], 1786 team_score=payload["teamScore"]["basic"]["value"], 1787 ) 1788 1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 ) 1818 1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 ) 1828 1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 ) 1856 1857 def _deserialize_extended_values( 1858 self, payload: typedefs.JSONObject 1859 ) -> activity.ExtendedValues: 1860 weapons: typing.Optional[ 1861 collections.Collection[activity.ExtendedWeaponValues] 1862 ] = None 1863 1864 if raw_weapons := payload.get("weapons"): 1865 weapons = [ 1866 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1867 ] 1868 1869 return activity.ExtendedValues( 1870 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1871 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1872 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1873 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1874 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1875 weapons=weapons, 1876 ) 1877 1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1910 character_class=character_class, 1911 character_level=character_level, 1912 race_hash=race_hash, 1913 gender_hash=gender_hash, 1914 class_hash=class_hash, 1915 light_level=int(player["lightLevel"]), 1916 emblem_hash=int(player["emblemHash"]), 1917 values=self._deserialize_activity_values(payload["values"]), 1918 extended_values=self._deserialize_extended_values(payload["extended"]), 1919 ) 1920 1921 def _deserialize_post_activity_team( 1922 self, payload: typedefs.JSONObject 1923 ) -> activity.PostActivityTeam: 1924 return activity.PostActivityTeam( 1925 id=payload["teamId"], 1926 is_defeated=bool(payload["standing"]["basic"]["value"]), 1927 score=int(payload["score"]["basic"]["value"]), 1928 name=payload["teamName"], 1929 ) 1930 1931 def deserialize_post_activity( 1932 self, payload: typedefs.JSONObject 1933 ) -> activity.PostActivity: 1934 period = time.clean_date(payload["period"]) 1935 details = payload["activityDetails"] 1936 ref_id = int(details["referenceId"]) 1937 instance_id = int(details["instanceId"]) 1938 mode = enums.GameMode(details["mode"]) 1939 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1940 is_private = details["isPrivate"] 1941 membership_type = enums.MembershipType(int(details["membershipType"])) 1942 return activity.PostActivity( 1943 net=self._net, 1944 hash=ref_id, 1945 membership_type=membership_type, 1946 instance_id=instance_id, 1947 mode=mode, 1948 modes=modes, 1949 is_private=is_private, 1950 occurred_at=period, 1951 starting_phase=int(payload["startingPhaseIndex"]), 1952 players=[ 1953 self.deserialize_post_activity_player(player) 1954 for player in payload["entries"] 1955 ], 1956 teams=[ 1957 self._deserialize_post_activity_team(team) for team in payload["teams"] 1958 ], 1959 ) 1960 1961 def _deserialize_aggregated_activity_values( 1962 self, payload: typedefs.JSONObject 1963 ) -> activity.AggregatedActivityValues: 1964 # This ID is always the same for all aggregated values. 1965 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1966 1967 return activity.AggregatedActivityValues( 1968 id=activity_id, 1969 fastest_completion_time=( 1970 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1971 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1972 ), 1973 completions=int(payload["activityCompletions"]["basic"]["value"]), 1974 kills=int(payload["activityKills"]["basic"]["value"]), 1975 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1976 assists=int(payload["activityAssists"]["basic"]["value"]), 1977 seconds_played=( 1978 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1979 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1980 ), 1981 wins=int(payload["activityWins"]["basic"]["value"]), 1982 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1983 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1984 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1985 best_single_score=int( 1986 payload["activityBestSingleGameScore"]["basic"]["value"] 1987 ), 1988 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1989 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1990 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1991 kd_ratio=float( 1992 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1993 ), 1994 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1995 ) 1996 1997 def deserialize_aggregated_activity( 1998 self, payload: typedefs.JSONObject 1999 ) -> activity.AggregatedActivity: 2000 return activity.AggregatedActivity( 2001 hash=int(payload["activityHash"]), 2002 values=self._deserialize_aggregated_activity_values(payload["values"]), 2003 ) 2004 2005 def deserialize_aggregated_activities( 2006 self, payload: typedefs.JSONObject 2007 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2008 return iterators.FlatIterator( 2009 [ 2010 self.deserialize_aggregated_activity(activity) 2011 for activity in payload["activities"] 2012 ] 2013 ) 2014 2015 def deserialize_linked_profiles( 2016 self, payload: typedefs.JSONObject 2017 ) -> profile.LinkedProfile: 2018 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2019 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2020 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2021 2022 if raw_profile := payload.get("profiles"): 2023 for pfile in raw_profile: 2024 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2025 2026 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2027 for raw_error_pfile in raw_profiles_with_errors: 2028 if error_pfile := raw_error_pfile.get("infoCard"): 2029 error_profiles_vec.append( 2030 self.deserialize_destiny_membership(error_pfile) 2031 ) 2032 2033 return profile.LinkedProfile( 2034 net=self._net, 2035 bungie=bungie_user, 2036 profiles=profiles_vec, 2037 profiles_with_errors=error_profiles_vec, 2038 ) 2039 2040 def deserialize_clan_banners( 2041 self, payload: typedefs.JSONObject 2042 ) -> collections.Sequence[clans.ClanBanner]: 2043 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2044 if banners := payload.get("clanBannerDecals"): 2045 for k, v in banners.items(): 2046 banner_obj = clans.ClanBanner( 2047 id=int(k), 2048 foreground=assets.Image(v["foregroundPath"]), 2049 background=assets.Image(v["backgroundPath"]), 2050 ) 2051 banners_seq.append(banner_obj) 2052 return banners_seq 2053 2054 def deserialize_public_milestone_content( 2055 self, payload: typedefs.JSONObject 2056 ) -> milestones.MilestoneContent: 2057 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2058 if raw_categories := payload.get("itemCategories"): 2059 for item in raw_categories: 2060 title = undefined.Undefined 2061 if raw_title := item.get("title"): 2062 if raw_title != typedefs.Unknown: 2063 title = raw_title 2064 if raw_hashes := item.get("itemHashes"): 2065 hashes: collections.Sequence[int] = raw_hashes 2066 2067 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2068 2069 about = undefined.Undefined 2070 if (raw_about := payload["about"]) != typedefs.Unknown: 2071 about = raw_about 2072 2073 status = undefined.Undefined 2074 if (raw_status := payload["status"]) != typedefs.Unknown: 2075 status = raw_status 2076 2077 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2078 if raw_tips := payload.get("tips"): 2079 for raw_tip in raw_tips: 2080 if raw_tip == typedefs.Unknown: 2081 raw_tip = undefined.Undefined 2082 tips.append(raw_tip) 2083 2084 return milestones.MilestoneContent( 2085 about=about, status=status, tips=tips, items=items_categoris 2086 ) 2087 2088 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2089 name = undefined.Undefined 2090 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2091 name = raw_name 2092 2093 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2094 2095 if raw_bungie_user := payload.get("bungieNetUser"): 2096 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2097 2098 return friends.Friend( 2099 net=self._net, 2100 id=int(payload["lastSeenAsMembershipId"]), 2101 name=name, 2102 code=payload.get("bungieGlobalDisplayNameCode"), 2103 relationship=enums.Relationship(payload["relationship"]), 2104 user=bungie_user, 2105 online_status=enums.Presence(payload["onlineStatus"]), 2106 online_title=payload["onlineTitle"], 2107 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2108 ) 2109 2110 def deserialize_friends( 2111 self, payload: typedefs.JSONObject 2112 ) -> collections.Sequence[friends.Friend]: 2113 mut_seq: typing.MutableSequence[friends.Friend] = [] 2114 if raw_friends := payload.get("friends"): 2115 for friend in raw_friends: 2116 mut_seq.append(self.deserialize_friend(friend)) 2117 return mut_seq 2118 2119 def deserialize_friend_requests( 2120 self, payload: typedefs.JSONObject 2121 ) -> friends.FriendRequestView: 2122 incoming: typing.MutableSequence[friends.Friend] = [] 2123 outgoing: typing.MutableSequence[friends.Friend] = [] 2124 2125 if raw_incoming_requests := payload.get("incomingRequests"): 2126 for incoming_request in raw_incoming_requests: 2127 incoming.append(self.deserialize_friend(incoming_request)) 2128 2129 if raw_outgoing_requests := payload.get("outgoingRequests"): 2130 for outgoing_request in raw_outgoing_requests: 2131 outgoing.append(self.deserialize_friend(outgoing_request)) 2132 2133 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2134 2135 def _set_fireteam_fields( 2136 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2137 ) -> fireteams.Fireteam: 2138 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2139 return fireteams.Fireteam( 2140 id=int(payload["fireteamId"]), 2141 group_id=int(payload["groupId"]), 2142 platform=fireteams.FireteamPlatform(payload["platform"]), 2143 is_immediate=payload["isImmediate"], 2144 activity_type=activity_type, 2145 owner_id=int(payload["ownerMembershipId"]), 2146 player_slot_count=payload["playerSlotCount"], 2147 available_player_slots=payload["availablePlayerSlotCount"], 2148 available_alternate_slots=payload["availableAlternateSlotCount"], 2149 title=payload["title"], 2150 date_created=time.clean_date(payload["dateCreated"]), 2151 is_public=payload["isPublic"], 2152 locale=fireteams.FireteamLanguage(payload["locale"]), 2153 is_valid=payload["isValid"], 2154 last_modified=time.clean_date(payload["datePlayerModified"]), 2155 total_results=total_results or 0, 2156 ) 2157 2158 def deserialize_fireteams( 2159 self, payload: typedefs.JSONObject 2160 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2161 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2162 2163 result: list[typedefs.JSONObject] 2164 if not (result := payload["results"]): 2165 return None 2166 for elem in result: 2167 fireteams_.append( 2168 self._set_fireteam_fields( 2169 elem, total_results=int(payload["totalResults"]) 2170 ) 2171 ) 2172 return fireteams_ 2173 2174 def deserialize_fireteam_destiny_users( 2175 self, payload: typedefs.JSONObject 2176 ) -> fireteams.FireteamUser: 2177 destiny_obj = self.deserialize_destiny_membership(payload) 2178 # We could helpers.just return a DestinyMembership object but this is 2179 # missing the fireteam display name and id fields. 2180 return fireteams.FireteamUser( 2181 net=self._net, 2182 id=destiny_obj.id, 2183 code=destiny_obj.code, 2184 icon=destiny_obj.icon, 2185 types=destiny_obj.types, 2186 type=destiny_obj.type, 2187 is_public=destiny_obj.is_public, 2188 crossave_override=destiny_obj.crossave_override, 2189 name=destiny_obj.name, 2190 last_seen_name=destiny_obj.last_seen_name, 2191 fireteam_display_name=payload["FireteamDisplayName"], 2192 fireteam_membership_id=enums.MembershipType( 2193 payload["FireteamMembershipType"] 2194 ), 2195 ) 2196 2197 def deserialize_fireteam_members( 2198 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2199 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2200 members_: list[fireteams.FireteamMember] = [] 2201 if members := payload.get("Members" if not alternatives else "Alternates"): 2202 for member in members: 2203 bungie_fields = self.deserialize_partial_bungie_user(member) 2204 members_fields = fireteams.FireteamMember( 2205 destiny_user=self.deserialize_fireteam_destiny_users(member), 2206 has_microphone=member["hasMicrophone"], 2207 character_id=int(member["characterId"]), 2208 date_joined=time.clean_date(member["dateJoined"]), 2209 last_platform_invite_date=time.clean_date( 2210 member["lastPlatformInviteAttemptDate"] 2211 ), 2212 last_platform_invite_result=int( 2213 member["lastPlatformInviteAttemptResult"] 2214 ), 2215 net=self._net, 2216 name=bungie_fields.name, 2217 id=bungie_fields.id, 2218 icon=bungie_fields.icon, 2219 is_public=bungie_fields.is_public, 2220 crossave_override=bungie_fields.crossave_override, 2221 types=bungie_fields.types, 2222 type=bungie_fields.type, 2223 ) 2224 members_.append(members_fields) 2225 else: 2226 return None 2227 return members_ 2228 2229 def deserialize_available_fireteams( 2230 self, 2231 data: typedefs.JSONObject, 2232 *, 2233 no_results: bool = False, 2234 ) -> typing.Union[ 2235 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2236 ]: 2237 fireteams_: list[fireteams.AvailableFireteam] = [] 2238 2239 # This needs to be used outside the results 2240 # JSON key. 2241 if no_results is True: 2242 payload = data 2243 2244 if result := payload.get("results"): 2245 2246 for fireteam in result: 2247 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2248 fireteams_fields = fireteams.AvailableFireteam( 2249 id=found_fireteams.id, 2250 group_id=found_fireteams.group_id, 2251 platform=found_fireteams.platform, 2252 activity_type=found_fireteams.activity_type, 2253 is_immediate=found_fireteams.is_immediate, 2254 is_public=found_fireteams.is_public, 2255 is_valid=found_fireteams.is_valid, 2256 owner_id=found_fireteams.owner_id, 2257 player_slot_count=found_fireteams.player_slot_count, 2258 available_player_slots=found_fireteams.available_player_slots, 2259 available_alternate_slots=found_fireteams.available_alternate_slots, 2260 title=found_fireteams.title, 2261 date_created=found_fireteams.date_created, 2262 locale=found_fireteams.locale, 2263 last_modified=found_fireteams.last_modified, 2264 total_results=found_fireteams.total_results, 2265 members=self.deserialize_fireteam_members(payload), 2266 alternatives=self.deserialize_fireteam_members( 2267 payload, alternatives=True 2268 ), 2269 ) 2270 fireteams_.append(fireteams_fields) 2271 if no_results: 2272 return fireteams_fields 2273 return fireteams_ 2274 2275 def deserialize_fireteam_party( 2276 self, payload: typedefs.JSONObject 2277 ) -> fireteams.FireteamParty: 2278 last_destination_hash: typing.Optional[int] = None 2279 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2280 last_destination_hash = int(raw_dest_hash) 2281 2282 return fireteams.FireteamParty( 2283 members=[ 2284 self._deserialize_fireteam_party_member(member) 2285 for member in payload["partyMembers"] 2286 ], 2287 activity=self._deserialize_fireteam_party_current_activity( 2288 payload["currentActivity"] 2289 ), 2290 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2291 last_destination_hash=last_destination_hash, 2292 tracking=payload["tracking"], 2293 ) 2294 2295 def _deserialize_fireteam_party_member( 2296 self, payload: typedefs.JSONObject 2297 ) -> fireteams.FireteamPartyMember: 2298 2299 status = fireteams.FireteamPartyMemberState(payload["status"]) 2300 displayname: undefined.UndefinedOr[str] = undefined.Undefined 2301 if raw_name := payload.get("displayName"): 2302 displayname = raw_name 2303 2304 return fireteams.FireteamPartyMember( 2305 membership_id=int(payload["membershipId"]), 2306 emblem_hash=int(payload["emblemHash"]), 2307 status=status, 2308 display_name=displayname, 2309 ) 2310 2311 def _deserialize_fireteam_party_current_activity( 2312 self, payload: typedefs.JSONObject 2313 ) -> fireteams.FireteamPartyCurrentActivity: 2314 start_date: typing.Optional[datetime.datetime] = None 2315 if raw_start_date := payload.get("startTime"): 2316 start_date = time.clean_date(raw_start_date) 2317 2318 end_date: typing.Optional[datetime.datetime] = None 2319 if raw_end_date := payload.get("endTime"): 2320 end_date = time.clean_date(raw_end_date) 2321 return fireteams.FireteamPartyCurrentActivity( 2322 start_time=start_date, 2323 end_time=end_date, 2324 score=float(payload["score"]), 2325 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2326 opponenst_count=int(payload["numberOfOpponents"]), 2327 player_count=int(payload["numberOfPlayers"]), 2328 ) 2329 2330 def _deserialize_fireteam_party_settings( 2331 self, payload: typedefs.JSONObject 2332 ) -> fireteams.FireteamPartySettings: 2333 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2334 return fireteams.FireteamPartySettings( 2335 open_slots=int(payload["openSlots"]), 2336 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2337 closed_reasons=closed_reasons, 2338 ) 2339 2340 def deserialize_seasonal_artifact( 2341 self, payload: typedefs.JSONObject 2342 ) -> season.Artifact: 2343 if raw_artifact := payload.get("seasonalArtifact"): 2344 if points := raw_artifact.get("pointProgression"): 2345 points_prog = progressions.Progression( 2346 hash=points["progressionHash"], 2347 level=points["level"], 2348 cap=points["levelCap"], 2349 daily_limit=points["dailyLimit"], 2350 weekly_limit=points["weeklyLimit"], 2351 current_progress=points["currentProgress"], 2352 daily_progress=points["dailyProgress"], 2353 needed=points["progressToNextLevel"], 2354 next_level=points["nextLevelAt"], 2355 ) 2356 2357 if bonus := raw_artifact.get("powerBonusProgression"): 2358 power_bonus_prog = progressions.Progression( 2359 hash=bonus["progressionHash"], 2360 level=bonus["level"], 2361 cap=bonus["levelCap"], 2362 daily_limit=bonus["dailyLimit"], 2363 weekly_limit=bonus["weeklyLimit"], 2364 current_progress=bonus["currentProgress"], 2365 daily_progress=bonus["dailyProgress"], 2366 needed=bonus["progressToNextLevel"], 2367 next_level=bonus["nextLevelAt"], 2368 ) 2369 artifact = season.Artifact( 2370 net=self._net, 2371 hash=raw_artifact["artifactHash"], 2372 power_bonus=raw_artifact["powerBonus"], 2373 acquired_points=raw_artifact["pointsAcquired"], 2374 bonus=power_bonus_prog, 2375 points=points_prog, 2376 ) 2377 return artifact 2378 2379 def deserialize_profile_progression( 2380 self, payload: typedefs.JSONObject 2381 ) -> profile.ProfileProgression: 2382 return profile.ProfileProgression( 2383 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2384 checklist={ 2385 int(check_id): checklists 2386 for check_id, checklists in payload["data"]["checklists"].items() 2387 }, 2388 ) 2389 2390 def deserialize_instanced_item( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.ItemInstance: 2393 damage_type_hash: typing.Optional[int] = None 2394 if raw_damagetype_hash := payload.get("damageTypeHash"): 2395 damage_type_hash = int(raw_damagetype_hash) 2396 2397 required_hashes: typing.Optional[collections.Collection[int]] = None 2398 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2399 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2400 2401 breaker_type: typing.Optional[items.ItemBreakerType] = None 2402 if raw_break_type := payload.get("breakerType"): 2403 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2404 2405 breaker_type_hash: typing.Optional[int] = None 2406 if raw_break_type_hash := payload.get("breakerTypeHash"): 2407 breaker_type_hash = int(raw_break_type_hash) 2408 2409 energy: typing.Optional[items.ItemEnergy] = None 2410 if raw_energy := payload.get("energy"): 2411 energy = self.deserialize_item_energy(raw_energy) 2412 2413 primary_stats = None 2414 if raw_primary_stats := payload.get("primaryStat"): 2415 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2416 2417 return items.ItemInstance( 2418 damage_type=enums.DamageType(int(payload["damageType"])), 2419 damage_type_hash=damage_type_hash, 2420 primary_stat=primary_stats, 2421 item_level=int(payload["itemLevel"]), 2422 quality=int(payload["quality"]), 2423 is_equipped=payload["isEquipped"], 2424 can_equip=payload["canEquip"], 2425 equip_required_level=int(payload["equipRequiredLevel"]), 2426 required_equip_unlock_hashes=required_hashes, 2427 cant_equip_reason=int(payload["cannotEquipReason"]), 2428 breaker_type=breaker_type, 2429 breaker_type_hash=breaker_type_hash, 2430 energy=energy, 2431 ) 2432 2433 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2434 energy_hash: typing.Optional[int] = None 2435 if raw_energy_hash := payload.get("energyTypeHash"): 2436 energy_hash = int(raw_energy_hash) 2437 2438 return items.ItemEnergy( 2439 hash=energy_hash, 2440 type=items.ItemEnergyType(int(payload["energyType"])), 2441 capacity=int(payload["energyCapacity"]), 2442 used_energy=int(payload["energyUsed"]), 2443 unused_energy=int(payload["energyUnused"]), 2444 ) 2445 2446 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2447 perk_hash: typing.Optional[int] = None 2448 if raw_perk_hash := payload.get("perkHash"): 2449 perk_hash = int(raw_perk_hash) 2450 2451 return items.ItemPerk( 2452 hash=perk_hash, 2453 icon=assets.Image(payload["iconPath"]), 2454 is_active=payload["isActive"], 2455 is_visible=payload["visible"], 2456 ) 2457 2458 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2459 plug_hash: typing.Optional[int] = None 2460 if raw_plug_hash := payload.get("plugHash"): 2461 plug_hash = int(raw_plug_hash) 2462 2463 enable_fail_indexes: typing.Optional[list[int]] = None 2464 if raw_indexes := payload.get("enableFailIndexes"): 2465 enable_fail_indexes = [int(index) for index in raw_indexes] 2466 2467 return items.ItemSocket( 2468 plug_hash=plug_hash, 2469 is_enabled=payload["isEnabled"], 2470 enable_fail_indexes=enable_fail_indexes, 2471 is_visible=payload.get("visible"), 2472 ) 2473 2474 def deserialize_item_stats_view( 2475 self, payload: typedefs.JSONObject 2476 ) -> items.ItemStatsView: 2477 return items.ItemStatsView( 2478 stat_hash=payload.get("statHash"), value=payload.get("value") 2479 ) 2480 2481 def deserialize_plug_item_state( 2482 self, payload: typedefs.JSONObject 2483 ) -> items.PlugItemState: 2484 item_hash: typing.Optional[int] = None 2485 if raw_item_hash := payload.get("plugItemHash"): 2486 item_hash = int(raw_item_hash) 2487 2488 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2489 if raw_fail_indexes := payload.get("insertFailIndexes"): 2490 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2491 2492 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2493 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2494 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2495 2496 return items.PlugItemState( 2497 item_hash=item_hash, 2498 insert_fail_indexes=insert_fail_indexes, 2499 enable_fail_indexes=enable_fail_indexes, 2500 is_enabled=payload["enabled"], 2501 can_insert=payload["canInsert"], 2502 )
The base deserialization factory class for all aiobungie objects.
Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ]
214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload))
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[aiobungie.crates.Profile]: A profile.
438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.ProfileItemImpl]]: A profile component object that contains items of the deserialized payload.
674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 )
775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 )
885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 )
928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions
939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 }
951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 }
1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 )
1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 )
Deserialize a JSON objects within the itemComponents key.`
1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1910 character_class=character_class, 1911 character_level=character_level, 1912 race_hash=race_hash, 1913 gender_hash=gender_hash, 1914 class_hash=class_hash, 1915 light_level=int(player["lightLevel"]), 1916 emblem_hash=int(player["emblemHash"]), 1917 values=self._deserialize_activity_values(payload["values"]), 1918 extended_values=self._deserialize_extended_values(payload["extended"]), 1919 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1931 def deserialize_post_activity( 1932 self, payload: typedefs.JSONObject 1933 ) -> activity.PostActivity: 1934 period = time.clean_date(payload["period"]) 1935 details = payload["activityDetails"] 1936 ref_id = int(details["referenceId"]) 1937 instance_id = int(details["instanceId"]) 1938 mode = enums.GameMode(details["mode"]) 1939 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1940 is_private = details["isPrivate"] 1941 membership_type = enums.MembershipType(int(details["membershipType"])) 1942 return activity.PostActivity( 1943 net=self._net, 1944 hash=ref_id, 1945 membership_type=membership_type, 1946 instance_id=instance_id, 1947 mode=mode, 1948 modes=modes, 1949 is_private=is_private, 1950 occurred_at=period, 1951 starting_phase=int(payload["startingPhaseIndex"]), 1952 players=[ 1953 self.deserialize_post_activity_player(player) 1954 for player in payload["entries"] 1955 ], 1956 teams=[ 1957 self._deserialize_post_activity_team(team) for team in payload["teams"] 1958 ], 1959 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1997 def deserialize_aggregated_activity( 1998 self, payload: typedefs.JSONObject 1999 ) -> activity.AggregatedActivity: 2000 return activity.AggregatedActivity( 2001 hash=int(payload["activityHash"]), 2002 values=self._deserialize_aggregated_activity_values(payload["values"]), 2003 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
2005 def deserialize_aggregated_activities( 2006 self, payload: typedefs.JSONObject 2007 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2008 return iterators.FlatIterator( 2009 [ 2010 self.deserialize_aggregated_activity(activity) 2011 for activity in payload["activities"] 2012 ] 2013 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
2015 def deserialize_linked_profiles( 2016 self, payload: typedefs.JSONObject 2017 ) -> profile.LinkedProfile: 2018 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2019 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2020 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2021 2022 if raw_profile := payload.get("profiles"): 2023 for pfile in raw_profile: 2024 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2025 2026 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2027 for raw_error_pfile in raw_profiles_with_errors: 2028 if error_pfile := raw_error_pfile.get("infoCard"): 2029 error_profiles_vec.append( 2030 self.deserialize_destiny_membership(error_pfile) 2031 ) 2032 2033 return profile.LinkedProfile( 2034 net=self._net, 2035 bungie=bungie_user, 2036 profiles=profiles_vec, 2037 profiles_with_errors=error_profiles_vec, 2038 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2054 def deserialize_public_milestone_content( 2055 self, payload: typedefs.JSONObject 2056 ) -> milestones.MilestoneContent: 2057 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2058 if raw_categories := payload.get("itemCategories"): 2059 for item in raw_categories: 2060 title = undefined.Undefined 2061 if raw_title := item.get("title"): 2062 if raw_title != typedefs.Unknown: 2063 title = raw_title 2064 if raw_hashes := item.get("itemHashes"): 2065 hashes: collections.Sequence[int] = raw_hashes 2066 2067 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2068 2069 about = undefined.Undefined 2070 if (raw_about := payload["about"]) != typedefs.Unknown: 2071 about = raw_about 2072 2073 status = undefined.Undefined 2074 if (raw_status := payload["status"]) != typedefs.Unknown: 2075 status = raw_status 2076 2077 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2078 if raw_tips := payload.get("tips"): 2079 for raw_tip in raw_tips: 2080 if raw_tip == typedefs.Unknown: 2081 raw_tip = undefined.Undefined 2082 tips.append(raw_tip) 2083 2084 return milestones.MilestoneContent( 2085 about=about, status=status, tips=tips, items=items_categoris 2086 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2088 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2089 name = undefined.Undefined 2090 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2091 name = raw_name 2092 2093 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2094 2095 if raw_bungie_user := payload.get("bungieNetUser"): 2096 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2097 2098 return friends.Friend( 2099 net=self._net, 2100 id=int(payload["lastSeenAsMembershipId"]), 2101 name=name, 2102 code=payload.get("bungieGlobalDisplayNameCode"), 2103 relationship=enums.Relationship(payload["relationship"]), 2104 user=bungie_user, 2105 online_status=enums.Presence(payload["onlineStatus"]), 2106 online_title=payload["onlineTitle"], 2107 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2108 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2110 def deserialize_friends( 2111 self, payload: typedefs.JSONObject 2112 ) -> collections.Sequence[friends.Friend]: 2113 mut_seq: typing.MutableSequence[friends.Friend] = [] 2114 if raw_friends := payload.get("friends"): 2115 for friend in raw_friends: 2116 mut_seq.append(self.deserialize_friend(friend)) 2117 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2119 def deserialize_friend_requests( 2120 self, payload: typedefs.JSONObject 2121 ) -> friends.FriendRequestView: 2122 incoming: typing.MutableSequence[friends.Friend] = [] 2123 outgoing: typing.MutableSequence[friends.Friend] = [] 2124 2125 if raw_incoming_requests := payload.get("incomingRequests"): 2126 for incoming_request in raw_incoming_requests: 2127 incoming.append(self.deserialize_friend(incoming_request)) 2128 2129 if raw_outgoing_requests := payload.get("outgoingRequests"): 2130 for outgoing_request in raw_outgoing_requests: 2131 outgoing.append(self.deserialize_friend(outgoing_request)) 2132 2133 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2158 def deserialize_fireteams( 2159 self, payload: typedefs.JSONObject 2160 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2161 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2162 2163 result: list[typedefs.JSONObject] 2164 if not (result := payload["results"]): 2165 return None 2166 for elem in result: 2167 fireteams_.append( 2168 self._set_fireteam_fields( 2169 elem, total_results=int(payload["totalResults"]) 2170 ) 2171 ) 2172 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2174 def deserialize_fireteam_destiny_users( 2175 self, payload: typedefs.JSONObject 2176 ) -> fireteams.FireteamUser: 2177 destiny_obj = self.deserialize_destiny_membership(payload) 2178 # We could helpers.just return a DestinyMembership object but this is 2179 # missing the fireteam display name and id fields. 2180 return fireteams.FireteamUser( 2181 net=self._net, 2182 id=destiny_obj.id, 2183 code=destiny_obj.code, 2184 icon=destiny_obj.icon, 2185 types=destiny_obj.types, 2186 type=destiny_obj.type, 2187 is_public=destiny_obj.is_public, 2188 crossave_override=destiny_obj.crossave_override, 2189 name=destiny_obj.name, 2190 last_seen_name=destiny_obj.last_seen_name, 2191 fireteam_display_name=payload["FireteamDisplayName"], 2192 fireteam_membership_id=enums.MembershipType( 2193 payload["FireteamMembershipType"] 2194 ), 2195 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2197 def deserialize_fireteam_members( 2198 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2199 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2200 members_: list[fireteams.FireteamMember] = [] 2201 if members := payload.get("Members" if not alternatives else "Alternates"): 2202 for member in members: 2203 bungie_fields = self.deserialize_partial_bungie_user(member) 2204 members_fields = fireteams.FireteamMember( 2205 destiny_user=self.deserialize_fireteam_destiny_users(member), 2206 has_microphone=member["hasMicrophone"], 2207 character_id=int(member["characterId"]), 2208 date_joined=time.clean_date(member["dateJoined"]), 2209 last_platform_invite_date=time.clean_date( 2210 member["lastPlatformInviteAttemptDate"] 2211 ), 2212 last_platform_invite_result=int( 2213 member["lastPlatformInviteAttemptResult"] 2214 ), 2215 net=self._net, 2216 name=bungie_fields.name, 2217 id=bungie_fields.id, 2218 icon=bungie_fields.icon, 2219 is_public=bungie_fields.is_public, 2220 crossave_override=bungie_fields.crossave_override, 2221 types=bungie_fields.types, 2222 type=bungie_fields.type, 2223 ) 2224 members_.append(members_fields) 2225 else: 2226 return None 2227 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.FireteamUser]]: An optional sequence of the fireteam members.
2229 def deserialize_available_fireteams( 2230 self, 2231 data: typedefs.JSONObject, 2232 *, 2233 no_results: bool = False, 2234 ) -> typing.Union[ 2235 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2236 ]: 2237 fireteams_: list[fireteams.AvailableFireteam] = [] 2238 2239 # This needs to be used outside the results 2240 # JSON key. 2241 if no_results is True: 2242 payload = data 2243 2244 if result := payload.get("results"): 2245 2246 for fireteam in result: 2247 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2248 fireteams_fields = fireteams.AvailableFireteam( 2249 id=found_fireteams.id, 2250 group_id=found_fireteams.group_id, 2251 platform=found_fireteams.platform, 2252 activity_type=found_fireteams.activity_type, 2253 is_immediate=found_fireteams.is_immediate, 2254 is_public=found_fireteams.is_public, 2255 is_valid=found_fireteams.is_valid, 2256 owner_id=found_fireteams.owner_id, 2257 player_slot_count=found_fireteams.player_slot_count, 2258 available_player_slots=found_fireteams.available_player_slots, 2259 available_alternate_slots=found_fireteams.available_alternate_slots, 2260 title=found_fireteams.title, 2261 date_created=found_fireteams.date_created, 2262 locale=found_fireteams.locale, 2263 last_modified=found_fireteams.last_modified, 2264 total_results=found_fireteams.total_results, 2265 members=self.deserialize_fireteam_members(payload), 2266 alternatives=self.deserialize_fireteam_members( 2267 payload, alternatives=True 2268 ), 2269 ) 2270 fireteams_.append(fireteams_fields) 2271 if no_results: 2272 return fireteams_fields 2273 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2275 def deserialize_fireteam_party( 2276 self, payload: typedefs.JSONObject 2277 ) -> fireteams.FireteamParty: 2278 last_destination_hash: typing.Optional[int] = None 2279 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2280 last_destination_hash = int(raw_dest_hash) 2281 2282 return fireteams.FireteamParty( 2283 members=[ 2284 self._deserialize_fireteam_party_member(member) 2285 for member in payload["partyMembers"] 2286 ], 2287 activity=self._deserialize_fireteam_party_current_activity( 2288 payload["currentActivity"] 2289 ), 2290 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2291 last_destination_hash=last_destination_hash, 2292 tracking=payload["tracking"], 2293 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2340 def deserialize_seasonal_artifact( 2341 self, payload: typedefs.JSONObject 2342 ) -> season.Artifact: 2343 if raw_artifact := payload.get("seasonalArtifact"): 2344 if points := raw_artifact.get("pointProgression"): 2345 points_prog = progressions.Progression( 2346 hash=points["progressionHash"], 2347 level=points["level"], 2348 cap=points["levelCap"], 2349 daily_limit=points["dailyLimit"], 2350 weekly_limit=points["weeklyLimit"], 2351 current_progress=points["currentProgress"], 2352 daily_progress=points["dailyProgress"], 2353 needed=points["progressToNextLevel"], 2354 next_level=points["nextLevelAt"], 2355 ) 2356 2357 if bonus := raw_artifact.get("powerBonusProgression"): 2358 power_bonus_prog = progressions.Progression( 2359 hash=bonus["progressionHash"], 2360 level=bonus["level"], 2361 cap=bonus["levelCap"], 2362 daily_limit=bonus["dailyLimit"], 2363 weekly_limit=bonus["weeklyLimit"], 2364 current_progress=bonus["currentProgress"], 2365 daily_progress=bonus["dailyProgress"], 2366 needed=bonus["progressToNextLevel"], 2367 next_level=bonus["nextLevelAt"], 2368 ) 2369 artifact = season.Artifact( 2370 net=self._net, 2371 hash=raw_artifact["artifactHash"], 2372 power_bonus=raw_artifact["powerBonus"], 2373 acquired_points=raw_artifact["pointsAcquired"], 2374 bonus=power_bonus_prog, 2375 points=points_prog, 2376 ) 2377 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2379 def deserialize_profile_progression( 2380 self, payload: typedefs.JSONObject 2381 ) -> profile.ProfileProgression: 2382 return profile.ProfileProgression( 2383 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2384 checklist={ 2385 int(check_id): checklists 2386 for check_id, checklists in payload["data"]["checklists"].items() 2387 }, 2388 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2390 def deserialize_instanced_item( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.ItemInstance: 2393 damage_type_hash: typing.Optional[int] = None 2394 if raw_damagetype_hash := payload.get("damageTypeHash"): 2395 damage_type_hash = int(raw_damagetype_hash) 2396 2397 required_hashes: typing.Optional[collections.Collection[int]] = None 2398 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2399 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2400 2401 breaker_type: typing.Optional[items.ItemBreakerType] = None 2402 if raw_break_type := payload.get("breakerType"): 2403 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2404 2405 breaker_type_hash: typing.Optional[int] = None 2406 if raw_break_type_hash := payload.get("breakerTypeHash"): 2407 breaker_type_hash = int(raw_break_type_hash) 2408 2409 energy: typing.Optional[items.ItemEnergy] = None 2410 if raw_energy := payload.get("energy"): 2411 energy = self.deserialize_item_energy(raw_energy) 2412 2413 primary_stats = None 2414 if raw_primary_stats := payload.get("primaryStat"): 2415 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2416 2417 return items.ItemInstance( 2418 damage_type=enums.DamageType(int(payload["damageType"])), 2419 damage_type_hash=damage_type_hash, 2420 primary_stat=primary_stats, 2421 item_level=int(payload["itemLevel"]), 2422 quality=int(payload["quality"]), 2423 is_equipped=payload["isEquipped"], 2424 can_equip=payload["canEquip"], 2425 equip_required_level=int(payload["equipRequiredLevel"]), 2426 required_equip_unlock_hashes=required_hashes, 2427 cant_equip_reason=int(payload["cannotEquipReason"]), 2428 breaker_type=breaker_type, 2429 breaker_type_hash=breaker_type_hash, 2430 energy=energy, 2431 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2433 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2434 energy_hash: typing.Optional[int] = None 2435 if raw_energy_hash := payload.get("energyTypeHash"): 2436 energy_hash = int(raw_energy_hash) 2437 2438 return items.ItemEnergy( 2439 hash=energy_hash, 2440 type=items.ItemEnergyType(int(payload["energyType"])), 2441 capacity=int(payload["energyCapacity"]), 2442 used_energy=int(payload["energyUsed"]), 2443 unused_energy=int(payload["energyUnused"]), 2444 )
2446 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2447 perk_hash: typing.Optional[int] = None 2448 if raw_perk_hash := payload.get("perkHash"): 2449 perk_hash = int(raw_perk_hash) 2450 2451 return items.ItemPerk( 2452 hash=perk_hash, 2453 icon=assets.Image(payload["iconPath"]), 2454 is_active=payload["isActive"], 2455 is_visible=payload["visible"], 2456 )
2458 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2459 plug_hash: typing.Optional[int] = None 2460 if raw_plug_hash := payload.get("plugHash"): 2461 plug_hash = int(raw_plug_hash) 2462 2463 enable_fail_indexes: typing.Optional[list[int]] = None 2464 if raw_indexes := payload.get("enableFailIndexes"): 2465 enable_fail_indexes = [int(index) for index in raw_indexes] 2466 2467 return items.ItemSocket( 2468 plug_hash=plug_hash, 2469 is_enabled=payload["isEnabled"], 2470 enable_fail_indexes=enable_fail_indexes, 2471 is_visible=payload.get("visible"), 2472 )
2481 def deserialize_plug_item_state( 2482 self, payload: typedefs.JSONObject 2483 ) -> items.PlugItemState: 2484 item_hash: typing.Optional[int] = None 2485 if raw_item_hash := payload.get("plugItemHash"): 2486 item_hash = int(raw_item_hash) 2487 2488 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2489 if raw_fail_indexes := payload.get("insertFailIndexes"): 2490 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2491 2492 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2493 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2494 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2495 2496 return items.PlugItemState( 2497 item_hash=item_hash, 2498 insert_fail_indexes=insert_fail_indexes, 2499 enable_fail_indexes=enable_fail_indexes, 2500 is_enabled=payload["enabled"], 2501 can_insert=payload["canInsert"], 2502 )
68@typing.final 69class FireteamActivity(int, enums.Enum): 70 """An enum for the fireteam activities.""" 71 72 ALL = 0 73 CRUCIBLE = 2 74 TRIALS_OF_OSIRIS = 3 75 NIGHTFALL = 4 76 ANY = 5 77 GAMBIT = 6 78 BLIND_WELL = 7 79 NIGHTMARE_HUNTS = 12 80 ALTARS_OF_SORROWS = 14 81 DUNGEON = 15 82 RAID_LW = 20 83 RAID_GOS = 21 84 RAID_DSC = 22 85 EXO_CHALLENGE = 23 86 S12_WRATHBORN = 24 87 EMPIRE_HUNTS = 25 88 S13_BATTLEGROUNDS = 26 89 EXOTIC_QUEST = 27 90 RAID_VOG = 28 91 S14_EXPUNGE = 30 92 S15_ASTRAL_ALIGNMENT = 31 93 S15_SHATTERED_RELAM = 32 94 SHATTERED_THRONE = 33 95 PROPHECY = 34 96 PIT_OF_HERESY = 35 97 DOE = 36 98 """Dares of Eternity.""" 99 DUNGEON_GOA = 37 100 """Grasp of Avarice.""" 101 VOW_OF_THE_DISCPILE = 38 102 CAMPAIGN = 39 103 WELLSPRING = 40 104 S16_BATTLEGROUNDS = 41 105 S17_NIGHTMARE_CONTAINMENT = 44 106 S17_SEVER = 45
An enum for the fireteam activities.
132@typing.final 133class FireteamDate(int, enums.Enum): 134 """An enum for fireteam date ranges.""" 135 136 ALL = 0 137 NOW = 1 138 TODAY = 2 139 TWO_DAYS = 3 140 THIS_WEEK = 4
An enum for fireteam date ranges.
109@typing.final 110class FireteamLanguage(str, enums.Enum): 111 """An enum for fireteams languages filters.""" 112 113 ALL = "" 114 ENGLISH = "en" 115 FRENCH = "fr" 116 ESPANOL = "es" 117 DEUTSCH = "de" 118 ITALIAN = "it" 119 JAPANESE = "ja" 120 PORTUGUESE = "pt-br" 121 RUSSIAN = "ru" 122 POLISH = "pl" 123 KOREAN = "ko" 124 # ? China 125 ZH_CHT = "zh-cht" 126 ZH_CHS = "zh-chs" 127 128 def __str__(self) -> str: 129 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
55@typing.final 56class FireteamPlatform(int, enums.Enum): 57 """An enum for fireteam related to bungie fireteams. 58 This is different from the normal `aiobungie.MembershipType`. 59 """ 60 61 ANY = 0 62 PSN_NETWORK = 1 63 XBOX_LIVE = 2 64 STEAM = 4 65 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
102class Flag(__enum.Flag): 103 """Builtin Python enum flag with extra handlings.""" 104 105 # Needs to type this here for mypy 106 _value_: int 107 108 @property 109 def name(self) -> str: # type: ignore[override] 110 if self._name_ is None: 111 self._name_ = f"UNKNOWN {self._value_}" 112 113 return self._name_ 114 115 @property 116 def value(self) -> int: # type: ignore[override] 117 return self._value_ 118 119 def __str__(self) -> str: 120 return self.name 121 122 def __repr__(self) -> str: 123 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 124 125 def __int__(self) -> int: 126 if isinstance(self.value, _ITERABLE): 127 raise TypeError( 128 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 129 ) 130 return int(self.value) 131 132 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 133 return self.__class__(self._value_ | int(other)) 134 135 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 136 return self.__class__(self._value_ ^ int(other)) 137 138 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 139 return self.__class__(other & int(other)) 140 141 def __invert__(self) -> Flag: 142 return self.__class__(~self._value_) 143 144 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 145 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
45class FlatIterator(typing.Generic[Item]): 46 """A Flat, In-Memory iterator for sequenced based data. 47 48 Example 49 ------- 50 ```py 51 iterator = FlatIterator([1, 2, 3]) 52 53 # Map the results. 54 for item in iterator.map(lambda item: item * 2): 55 print(item) 56 # 2 57 # 4 58 59 # Indexing is also supported. 60 print(iterator[0]) 61 # 1 62 63 # Normal iteration. 64 for item in iterator: 65 print(item) 66 # 1 67 # 2 68 # 3 69 70 # Union two iterators. 71 iterator2 = FlatIterator([4, 5, 6]) 72 final = iterator | iterator2 73 # <FlatIterator([1, 2, 3, 4, 5, 6])> 74 ``` 75 76 Parameters 77 ---------- 78 items: `collections.Iterable[Item]` 79 The items to iterate over. 80 """ 81 82 __slots__ = ("_items",) 83 84 def __init__(self, items: collections.Iterable[Item]) -> None: 85 self._items = iter(items) 86 87 @typing.overload 88 def collect(self) -> list[Item]: 89 ... 90 91 @typing.overload 92 def collect(self, casting: _B) -> list[_B]: 93 ... 94 95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = FlatIterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items) 120 121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = FlatIterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok() 143 144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> FlatIterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <FlatIterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `FlatIterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return FlatIterator(map(predicate, self._items)) 173 174 def take(self, n: int) -> FlatIterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return FlatIterator(itertools.islice(self._items, n)) 197 198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> FlatIterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = FlatIterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <FlatIterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return FlatIterator(itertools.takewhile(predicate, self._items)) 222 223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> FlatIterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <FlatIterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return FlatIterator(itertools.dropwhile(predicate, self._items)) 247 248 def filter( 249 self, predicate: collections.Callable[[Item], bool] 250 ) -> FlatIterator[Item]: 251 """Filters the iterator to only yield items that match the predicate. 252 253 Example 254 ------- 255 ```py 256 names = FlatIterator(["Jim", "Bob", "Mike", "Jess"]) 257 print(names.filter(lambda n: n != "Jim")) 258 # <FlatIterator(["Bob", "Mike", "Jess"])> 259 ``` 260 """ 261 return FlatIterator(filter(predicate, self._items)) 262 263 def skip(self, n: int) -> FlatIterator[Item]: 264 """Skips the first number of items in the iterator. 265 266 Example 267 ------- 268 ```py 269 iterator = FlatIterator([STEAM, XBOX, STADIA]) 270 print(iterator.skip(1)) 271 # <FlatIterator([XBOX, STADIA])> 272 ``` 273 """ 274 return FlatIterator(itertools.islice(self._items, n, None)) 275 276 def discard( 277 self, predicate: collections.Callable[[Item], bool] 278 ) -> FlatIterator[Item]: 279 """Discards all elements in the iterator for which the predicate function returns true. 280 281 Example 282 ------- 283 ```py 284 iterator = FlatIterator(['A', 'B', 'C']) 285 print(iterator.discard(lambda x: x == 'B')) 286 # <FlatIterator(['A', 'C'])> 287 ``` 288 289 Parameters 290 ---------- 291 predicate: `collections.Callable[[Item], bool]` 292 The function to test each item in the iterator. 293 294 Raises 295 ------ 296 `StopIteration` 297 If no elements are left in the iterator. 298 """ 299 return FlatIterator(filter(lambda x: not predicate(x), self._items)) 300 301 def zip( 302 self, other: FlatIterator[OtherItem] 303 ) -> FlatIterator[tuple[Item, OtherItem]]: 304 """Zips the iterator with another iterable. 305 306 Example 307 ------- 308 ```py 309 iterator = FlatIterator([1, 3, 5]) 310 other = FlatIterator([2, 4, 6]) 311 for item, other_item in iterator.zip(other): 312 print(item, other_item) 313 # <FlatIterator([(1, 2), (3, 4), (5, 6)])> 314 ``` 315 316 Parameters 317 ---------- 318 other: `FlatIterator[OtherItem]` 319 The iterable to zip with. 320 321 Raises 322 ------ 323 `StopIteration` 324 If no elements are left in the iterator. 325 """ 326 return FlatIterator(zip(self._items, other)) 327 328 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 329 """`True` if all items in the iterator match the predicate. 330 331 Example 332 ------- 333 ```py 334 iterator = FlatIterator([1, 2, 3]) 335 while iterator.all(lambda item: isinstance(item, int)): 336 print("Still all integers") 337 continue 338 # Still all integers 339 ``` 340 341 Parameters 342 ---------- 343 predicate: `collections.Callable[[Item], bool]` 344 The function to test each item in the iterator. 345 346 Raises 347 ------ 348 `StopIteration` 349 If no elements are left in the iterator. 350 """ 351 return all(predicate(item) for item in self) 352 353 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 354 """`True` if any items in the iterator match the predicate. 355 356 Example 357 ------- 358 ```py 359 iterator = FlatIterator([1, 2, 3]) 360 if iterator.any(lambda item: isinstance(item, int)): 361 print("At least one item is an int.") 362 # At least one item is an int. 363 ``` 364 365 Parameters 366 ---------- 367 predicate: `collections.Callable[[Item], bool]` 368 The function to test each item in the iterator. 369 370 Raises 371 ------ 372 `StopIteration` 373 If no elements are left in the iterator. 374 """ 375 return any(predicate(item) for item in self) 376 377 def sort( 378 self, 379 *, 380 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 381 reverse: bool = False, 382 ) -> FlatIterator[Item]: 383 """Sorts the iterator. 384 385 Example 386 ------- 387 ```py 388 iterator = FlatIterator([3, 1, 6, 7]) 389 print(iterator.sort(key=lambda item: item)) 390 # <FlatIterator([1, 3, 6, 7])> 391 ``` 392 393 Parameters 394 ---------- 395 key: `collections.Callable[[Item], Any]` 396 The function to sort by. 397 reverse: `bool` 398 Whether to reverse the sort. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return FlatIterator(sorted(self._items, key=key, reverse=reverse)) 406 407 def first(self) -> Item: 408 """Returns the first item in the iterator. 409 410 Example 411 ------- 412 ```py 413 iterator = FlatIterator([3, 1, 6, 7]) 414 print(iterator.first()) 415 3 416 ``` 417 418 Raises 419 ------ 420 `StopIteration` 421 If no elements are left in the iterator. 422 """ 423 return self.take(1).next() 424 425 def reversed(self) -> FlatIterator[Item]: 426 """Returns a new iterator that yields the items in the iterator in reverse order. 427 428 Example 429 ------- 430 ```py 431 iterator = FlatIterator([3, 1, 6, 7]) 432 print(iterator.reversed()) 433 # <FlatIterator([7, 6, 1, 3])> 434 ``` 435 436 Raises 437 ------ 438 `StopIteration` 439 If no elements are left in the iterator. 440 """ 441 return FlatIterator(reversed(self.collect())) 442 443 def count(self) -> int: 444 """Returns the number of items in the iterator. 445 446 Example 447 ------- 448 ```py 449 iterator = FlatIterator([3, 1, 6, 7]) 450 print(iterator.count()) 451 4 452 ``` 453 """ 454 count = 0 455 for _ in self: 456 count += 1 457 458 return count 459 460 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 461 """Returns a new iterator that yields all items from both iterators. 462 463 Example 464 ------- 465 ```py 466 iterator = FlatIterator([1, 2, 3]) 467 other = FlatIterator([4, 5, 6]) 468 print(iterator.union(other)) 469 # <FlatIterator([1, 2, 3, 4, 5, 6])> 470 ``` 471 472 Parameters 473 ---------- 474 other: `FlatIterator[Item]` 475 The iterable to union with. 476 477 Raises 478 ------ 479 `StopIteration` 480 If no elements are left in the iterator. 481 """ 482 return FlatIterator(itertools.chain(self._items, other)) 483 484 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 485 """Calls the function on each item in the iterator. 486 487 Example 488 ------- 489 ```py 490 iterator = FlatIterator([1, 2, 3]) 491 iterator.for_each(lambda item: print(item)) 492 # 1 493 # 2 494 # 3 495 ``` 496 497 Parameters 498 ---------- 499 func: `typeshed.Callable[[Item], None]` 500 The function to call on each item in the iterator. 501 """ 502 for item in self: 503 func(item) 504 505 async def async_for_each( 506 self, 507 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 508 ) -> None: 509 """Calls the async function on each item in the iterator concurrently. 510 511 Example 512 ------- 513 ```py 514 async def signup(username: str) -> None: 515 async with aiohttp.request('POST', '...') as r: 516 # Actual logic. 517 ... 518 519 async def main(): 520 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 521 await users.async_for_each(lambda username: signup(username)) 522 ``` 523 524 Parameters 525 ---------- 526 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 527 The async function to call on each item in the iterator. 528 """ 529 await _helpers.awaits(*(func(item) for item in self)) 530 531 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 532 """Returns a new iterator that yields tuples of the index and item. 533 534 Example 535 ------- 536 ```py 537 iterator = FlatIterator([1, 2, 3]) 538 for index, item in iterator.enumerate(): 539 print(index, item) 540 # 0 1 541 # 1 2 542 # 2 3 543 ``` 544 545 Raises 546 ------ 547 `StopIteration` 548 If no elements are left in the iterator. 549 """ 550 return FlatIterator(enumerate(self._items, start=start)) 551 552 def _ok(self) -> typing.NoReturn: 553 raise StopIteration("No more items in the iterator.") from None 554 555 def __getitem__(self, index: int) -> Item: 556 try: 557 return self.skip(index).first() 558 except IndexError: 559 self._ok() 560 561 def __or__(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 562 return self.union(other) 563 564 # This is a never. 565 def __setitem__(self) -> typing.NoReturn: 566 raise TypeError( 567 f"{type(self).__name__} doesn't support item assignment." 568 ) from None 569 570 def __repr__(self) -> str: 571 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 572 573 def __len__(self) -> int: 574 return self.count() 575 576 def __iter__(self) -> FlatIterator[Item]: 577 return self 578 579 def __next__(self) -> Item: 580 try: 581 item = next(self._items) 582 except StopIteration: 583 self._ok() 584 585 return item
A Flat, In-Memory iterator for sequenced based data.
Example
iterator = FlatIterator([1, 2, 3])
# Map the results.
for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# Indexing is also supported.
print(iterator[0])
# 1
# Normal iteration.
for item in iterator:
print(item)
# 1
# 2
# 3
# Union two iterators.
iterator2 = FlatIterator([4, 5, 6])
final = iterator | iterator2
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = FlatIterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items)
Collects all items in the iterator into a list and cast them into an object if provided.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
- casting (
T | None): The type to cast the items to. IfNoneis provided, the items will be returned as is.
Raises
StopIteration: If no elements are left in the iterator.
121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = FlatIterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok()
Returns the next item in the iterator.
Example
iterator = FlatIterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> FlatIterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <FlatIterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `FlatIterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return FlatIterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <FlatIterator([1, 2, 3])>
Parameters
- predicate (
collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
FlatIterator[OtherItem]: The mapped iterator.
Raises
StopIteration: If no elements are left in the iterator.
174 def take(self, n: int) -> FlatIterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return FlatIterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> FlatIterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = FlatIterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <FlatIterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return FlatIterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <FlatIterator([STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> FlatIterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <FlatIterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return FlatIterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
248 def filter( 249 self, predicate: collections.Callable[[Item], bool] 250 ) -> FlatIterator[Item]: 251 """Filters the iterator to only yield items that match the predicate. 252 253 Example 254 ------- 255 ```py 256 names = FlatIterator(["Jim", "Bob", "Mike", "Jess"]) 257 print(names.filter(lambda n: n != "Jim")) 258 # <FlatIterator(["Bob", "Mike", "Jess"])> 259 ``` 260 """ 261 return FlatIterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
names = FlatIterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <FlatIterator(["Bob", "Mike", "Jess"])>
263 def skip(self, n: int) -> FlatIterator[Item]: 264 """Skips the first number of items in the iterator. 265 266 Example 267 ------- 268 ```py 269 iterator = FlatIterator([STEAM, XBOX, STADIA]) 270 print(iterator.skip(1)) 271 # <FlatIterator([XBOX, STADIA])> 272 ``` 273 """ 274 return FlatIterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <FlatIterator([XBOX, STADIA])>
276 def discard( 277 self, predicate: collections.Callable[[Item], bool] 278 ) -> FlatIterator[Item]: 279 """Discards all elements in the iterator for which the predicate function returns true. 280 281 Example 282 ------- 283 ```py 284 iterator = FlatIterator(['A', 'B', 'C']) 285 print(iterator.discard(lambda x: x == 'B')) 286 # <FlatIterator(['A', 'C'])> 287 ``` 288 289 Parameters 290 ---------- 291 predicate: `collections.Callable[[Item], bool]` 292 The function to test each item in the iterator. 293 294 Raises 295 ------ 296 `StopIteration` 297 If no elements are left in the iterator. 298 """ 299 return FlatIterator(filter(lambda x: not predicate(x), self._items))
Discards all elements in the iterator for which the predicate function returns true.
Example
iterator = FlatIterator(['A', 'B', 'C'])
print(iterator.discard(lambda x: x == 'B'))
# <FlatIterator(['A', 'C'])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
301 def zip( 302 self, other: FlatIterator[OtherItem] 303 ) -> FlatIterator[tuple[Item, OtherItem]]: 304 """Zips the iterator with another iterable. 305 306 Example 307 ------- 308 ```py 309 iterator = FlatIterator([1, 3, 5]) 310 other = FlatIterator([2, 4, 6]) 311 for item, other_item in iterator.zip(other): 312 print(item, other_item) 313 # <FlatIterator([(1, 2), (3, 4), (5, 6)])> 314 ``` 315 316 Parameters 317 ---------- 318 other: `FlatIterator[OtherItem]` 319 The iterable to zip with. 320 321 Raises 322 ------ 323 `StopIteration` 324 If no elements are left in the iterator. 325 """ 326 return FlatIterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
iterator = FlatIterator([1, 3, 5])
other = FlatIterator([2, 4, 6])
for item, other_item in iterator.zip(other):
print(item, other_item)
# <FlatIterator([(1, 2), (3, 4), (5, 6)])>
Parameters
- other (
FlatIterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
328 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 329 """`True` if all items in the iterator match the predicate. 330 331 Example 332 ------- 333 ```py 334 iterator = FlatIterator([1, 2, 3]) 335 while iterator.all(lambda item: isinstance(item, int)): 336 print("Still all integers") 337 continue 338 # Still all integers 339 ``` 340 341 Parameters 342 ---------- 343 predicate: `collections.Callable[[Item], bool]` 344 The function to test each item in the iterator. 345 346 Raises 347 ------ 348 `StopIteration` 349 If no elements are left in the iterator. 350 """ 351 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
iterator = FlatIterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
353 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 354 """`True` if any items in the iterator match the predicate. 355 356 Example 357 ------- 358 ```py 359 iterator = FlatIterator([1, 2, 3]) 360 if iterator.any(lambda item: isinstance(item, int)): 361 print("At least one item is an int.") 362 # At least one item is an int. 363 ``` 364 365 Parameters 366 ---------- 367 predicate: `collections.Callable[[Item], bool]` 368 The function to test each item in the iterator. 369 370 Raises 371 ------ 372 `StopIteration` 373 If no elements are left in the iterator. 374 """ 375 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
iterator = FlatIterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
# At least one item is an int.
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
377 def sort( 378 self, 379 *, 380 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 381 reverse: bool = False, 382 ) -> FlatIterator[Item]: 383 """Sorts the iterator. 384 385 Example 386 ------- 387 ```py 388 iterator = FlatIterator([3, 1, 6, 7]) 389 print(iterator.sort(key=lambda item: item)) 390 # <FlatIterator([1, 3, 6, 7])> 391 ``` 392 393 Parameters 394 ---------- 395 key: `collections.Callable[[Item], Any]` 396 The function to sort by. 397 reverse: `bool` 398 Whether to reverse the sort. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return FlatIterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <FlatIterator([1, 3, 6, 7])>
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
407 def first(self) -> Item: 408 """Returns the first item in the iterator. 409 410 Example 411 ------- 412 ```py 413 iterator = FlatIterator([3, 1, 6, 7]) 414 print(iterator.first()) 415 3 416 ``` 417 418 Raises 419 ------ 420 `StopIteration` 421 If no elements are left in the iterator. 422 """ 423 return self.take(1).next()
Returns the first item in the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
StopIteration: If no elements are left in the iterator.
425 def reversed(self) -> FlatIterator[Item]: 426 """Returns a new iterator that yields the items in the iterator in reverse order. 427 428 Example 429 ------- 430 ```py 431 iterator = FlatIterator([3, 1, 6, 7]) 432 print(iterator.reversed()) 433 # <FlatIterator([7, 6, 1, 3])> 434 ``` 435 436 Raises 437 ------ 438 `StopIteration` 439 If no elements are left in the iterator. 440 """ 441 return FlatIterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.reversed())
# <FlatIterator([7, 6, 1, 3])>
Raises
StopIteration: If no elements are left in the iterator.
443 def count(self) -> int: 444 """Returns the number of items in the iterator. 445 446 Example 447 ------- 448 ```py 449 iterator = FlatIterator([3, 1, 6, 7]) 450 print(iterator.count()) 451 4 452 ``` 453 """ 454 count = 0 455 for _ in self: 456 count += 1 457 458 return count
Returns the number of items in the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.count())
4
460 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 461 """Returns a new iterator that yields all items from both iterators. 462 463 Example 464 ------- 465 ```py 466 iterator = FlatIterator([1, 2, 3]) 467 other = FlatIterator([4, 5, 6]) 468 print(iterator.union(other)) 469 # <FlatIterator([1, 2, 3, 4, 5, 6])> 470 ``` 471 472 Parameters 473 ---------- 474 other: `FlatIterator[Item]` 475 The iterable to union with. 476 477 Raises 478 ------ 479 `StopIteration` 480 If no elements are left in the iterator. 481 """ 482 return FlatIterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
iterator = FlatIterator([1, 2, 3])
other = FlatIterator([4, 5, 6])
print(iterator.union(other))
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
- other (
FlatIterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
484 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 485 """Calls the function on each item in the iterator. 486 487 Example 488 ------- 489 ```py 490 iterator = FlatIterator([1, 2, 3]) 491 iterator.for_each(lambda item: print(item)) 492 # 1 493 # 2 494 # 3 495 ``` 496 497 Parameters 498 ---------- 499 func: `typeshed.Callable[[Item], None]` 500 The function to call on each item in the iterator. 501 """ 502 for item in self: 503 func(item)
Calls the function on each item in the iterator.
Example
iterator = FlatIterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
505 async def async_for_each( 506 self, 507 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 508 ) -> None: 509 """Calls the async function on each item in the iterator concurrently. 510 511 Example 512 ------- 513 ```py 514 async def signup(username: str) -> None: 515 async with aiohttp.request('POST', '...') as r: 516 # Actual logic. 517 ... 518 519 async def main(): 520 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 521 await users.async_for_each(lambda username: signup(username)) 522 ``` 523 524 Parameters 525 ---------- 526 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 527 The async function to call on each item in the iterator. 528 """ 529 await _helpers.awaits(*(func(item) for item in self))
Calls the async function on each item in the iterator concurrently.
Example
async def signup(username: str) -> None:
async with aiohttp.request('POST', '...') as r:
# Actual logic.
...
async def main():
users = aiobungie.into_iter(["user_danny", "user_jojo"])
await users.async_for_each(lambda username: signup(username))
Parameters
- func (
collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
531 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 532 """Returns a new iterator that yields tuples of the index and item. 533 534 Example 535 ------- 536 ```py 537 iterator = FlatIterator([1, 2, 3]) 538 for index, item in iterator.enumerate(): 539 print(index, item) 540 # 0 1 541 # 1 2 542 # 2 3 543 ``` 544 545 Raises 546 ------ 547 `StopIteration` 548 If no elements are left in the iterator. 549 """ 550 return FlatIterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
iterator = FlatIterator([1, 2, 3])
for index, item in iterator.enumerate():
print(index, item)
# 0 1
# 1 2
# 2 3
Raises
StopIteration: If no elements are left in the iterator.
120@attrs.define(auto_exc=True) 121class Forbidden(HTTPException): 122 """Exception that's raised for when status code 403 occurs.""" 123 124 http_status: http.HTTPStatus = attrs.field( 125 default=http.HTTPStatus.FORBIDDEN, init=False 126 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
274@typing.final 275class GameMode(int, Enum): 276 """An Enum for all available gamemodes in Destiny 2.""" 277 278 NONE = 0 279 STORY = 2 280 STRIKE = 3 281 RAID = 4 282 ALLPVP = 5 283 PATROL = 6 284 ALLPVE = 7 285 RESERVED9 = 9 286 CONTROL = 10 287 RESERVED11 = 11 288 CLASH = 12 289 RESERVED13 = 13 290 CRIMSONDOUBLES = 15 291 NIGHTFALL = 16 292 HEROICNIGHTFALL = 17 293 ALLSTRIKES = 18 294 IRONBANNER = 19 295 RESERVED20 = 20 296 RESERVED21 = 21 297 RESERVED22 = 22 298 RESERVED24 = 24 299 ALLMAYHEM = 25 300 RESERVED26 = 26 301 RESERVED27 = 27 302 RESERVED28 = 28 303 RESERVED29 = 29 304 RESERVED30 = 30 305 SUPREMACY = 31 306 PRIVATEMATCHESALL = 32 307 SURVIVAL = 37 308 COUNTDOWN = 38 309 TRIALSOFTHENINE = 39 310 SOCIAL = 40 311 TRIALSCOUNTDOWN = 41 312 TRIALSSURVIVAL = 42 313 IRONBANNERCONTROL = 43 314 IRONBANNERCLASH = 44 315 IRONBANNERSUPREMACY = 45 316 SCOREDNIGHTFALL = 46 317 SCOREDHEROICNIGHTFALL = 47 318 RUMBLE = 48 319 ALLDOUBLES = 49 320 DOUBLES = 50 321 PRIVATEMATCHESCLASH = 51 322 PRIVATEMATCHESCONTROL = 52 323 PRIVATEMATCHESSUPREMACY = 53 324 PRIVATEMATCHESCOUNTDOWN = 54 325 PRIVATEMATCHESSURVIVAL = 55 326 PRIVATEMATCHESMAYHEM = 56 327 PRIVATEMATCHESRUMBLE = 57 328 HEROICADVENTURE = 58 329 SHOWDOWN = 59 330 LOCKDOWN = 60 331 SCORCHED = 61 332 SCORCHEDTEAM = 62 333 GAMBIT = 63 334 ALLPVECOMPETITIVE = 64 335 BREAKTHROUGH = 65 336 BLACKARMORYRUN = 66 337 SALVAGE = 67 338 IRONBANNERSALVAGE = 68 339 PVPCOMPETITIVE = 69 340 PVPQUICKPLAY = 70 341 CLASHQUICKPLAY = 71 342 CLASHCOMPETITIVE = 72 343 CONTROLQUICKPLAY = 73 344 CONTROLCOMPETITIVE = 74 345 GAMBITPRIME = 75 346 RECKONING = 76 347 MENAGERIE = 77 348 VEXOFFENSIVE = 78 349 NIGHTMAREHUNT = 79 350 ELIMINATION = 80 351 MOMENTUM = 81 352 DUNGEON = 82 353 SUNDIAL = 83 354 TRIALS_OF_OSIRIS = 84 355 DARES = 85 356 OFFENSIVE = 86 357 LOSTSECTOR = 87 358 RIFT = 88 359 ZONECONTROL = 89 360 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
487@typing.final 488class Gender(int, Enum): 489 """An Enum for Destiny Genders.""" 490 491 MALE = 0 492 FEMALE = 1 493 UNKNOWN = 2
An Enum for Destiny Genders.
656@typing.final 657class GroupType(int, Enum): 658 """An enums for the known bungie group types.""" 659 660 GENERAL = 0 661 CLAN = 1
An enums for the known bungie group types.
62@attrs.define(auto_exc=True) 63class HTTPError(AiobungieError): 64 """Exception base used for HTTP request errors.""" 65 66 message: str 67 """The error message.""" 68 69 http_status: http.HTTPStatus 70 """The response status."""
Exception base used for HTTP request errors.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
73@attrs.define(auto_exc=True, kw_only=True) 74class HTTPException(HTTPError): 75 """Exception base internally used for an HTTP request response errors.""" 76 77 error_code: int 78 """The returned Bungie error status code.""" 79 80 http_status: http.HTTPStatus 81 """The request response http status.""" 82 83 throttle_seconds: int 84 """The Bungie response throttle seconds.""" 85 86 url: typing.Optional[typedefs.StrOrURL] 87 """The URL/endpoint caused this error.""" 88 89 body: typing.Any 90 """The response body.""" 91 92 headers: multidict.CIMultiDictProxy[str] 93 """The response headers.""" 94 95 message: str 96 """A Bungie human readable message describes the cause of the error.""" 97 98 error_status: str 99 """A Bungie short error status describes the cause of the error.""" 100 101 message_data: dict[str, str] 102 """A dict of string key, value that includes each cause of the error 103 to a message describes information about that error. 104 """ 105 106 def __str__(self) -> str: 107 if self.message: 108 message_body = self.message 109 110 if self.error_status: 111 error_status_body = self.error_status 112 113 return ( 114 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 115 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 116 f"{str(self.body)}" 117 )
Exception base internally used for an HTTP request response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
72class Image: 73 """Representation of an image/avatar/picture at Bungie. 74 75 Example 76 ------- 77 ```py 78 from aiobungie import Image 79 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 80 print(img) 81 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 82 83 # Stream the image. 84 async for chunk in img: 85 # Byte chunks of the image. 86 print(chunk) 87 88 # Save the image to a file. 89 await img.save("file_name", "/my/path/to/save/to", "jpeg") 90 ``` 91 92 Parameters 93 ---------- 94 path : `str | None` 95 The path to the image. If `None`, the default missing image path will be used. 96 """ 97 98 __slots__ = ("_path",) 99 100 def __init__(self, path: typing.Optional[str] = None) -> None: 101 self._path = path 102 103 @property 104 def is_missing(self) -> bool: 105 return not self._path 106 107 @property 108 def url(self) -> str: 109 """The URL to the image.""" 110 return self.create_url() 111 112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png" 116 117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 126 127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err 181 182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader 204 205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk 224 225 def __repr__(self) -> str: 226 return f"Image(url={self.create_url()})" 227 228 def __str__(self) -> str: 229 return self.create_url() 230 231 def __aiter__(self) -> Image: 232 return self 233 234 async def __anext__(self) -> bytes: 235 return await self.read() 236 237 def __await__(self) -> collections.Generator[None, None, bytes]: 238 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
190@attrs.define(auto_exc=True) 191class InternalServerError(HTTPException): 192 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
722@typing.final 723class ItemBindStatus(int, Enum): 724 """An enum for Destiny 2 items bind status.""" 725 726 NOT_BOUND = 0 727 BOUND_TO_CHARACTER = 1 728 BOUND_TO_ACCOUNT = 2 729 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
732@typing.final 733class ItemLocation(int, Enum): 734 """An enum for Destiny 2 items location.""" 735 736 UNKNOWN = 0 737 INVENTORY = 1 738 VAULT = 2 739 VENDOR = 3 740 POSTMASTER = 4
An enum for Destiny 2 items location.
757@typing.final 758class ItemState(Flag): 759 """An enum for Destiny 2 item states.""" 760 761 NONE = 0 762 LOCKED = 1 763 TRACKED = 2 764 MASTERWORKED = 4 765 CRAFTED = 8 766 """If this bit is set, the item has been 'crafted' by the player.""" 767 HIGHLITED_OBJECTIVE = 16 768 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
589@typing.final 590class ItemSubType(int, Enum): 591 """An enum for Destiny 2 inventory items subtype.""" 592 593 NONE = 0 594 AUTORIFLE = 6 595 SHOTGUN = 7 596 MACHINEGUN = 8 597 HANDCANNON = 9 598 ROCKETLAUNCHER = 10 599 FUSIONRIFLE = 11 600 SNIPERRIFLE = 12 601 PULSERIFLE = 13 602 SCOUTRIFLE = 14 603 SIDEARM = 17 604 SWORD = 18 605 MASK = 19 606 SHADER = 20 607 ORNAMENT = 21 608 FUSIONRIFLELINE = 22 609 GRENADELAUNCHER = 23 610 SUBMACHINEGUN = 24 611 TRACERIFLE = 25 612 HELMETARMOR = 26 613 GAUNTLETSARMOR = 27 614 CHESTARMOR = 28 615 LEGARMOR = 29 616 CLASSARMOR = 30 617 BOW = 31 618 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
621@typing.final 622class ItemTier(int, Enum): 623 """An enum for a Destiny 2 item tier.""" 624 625 NONE = 0 626 BASIC = 3340296461 627 COMMON = 2395677314 628 RARE = 2127292149 629 LEGENDERY = 4008398120 630 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
556@typing.final 557class ItemType(int, Enum): 558 """Enums for Destiny2's item types.""" 559 560 NONE = 0 561 CURRENCY = 1 562 ARMOR = 2 563 WEAPON = 3 564 MESSAGE = 7 565 ENGRAM = 8 566 CONSUMABLE = 9 567 EXCHANGEMATERIAL = 10 568 MISSIONREWARD = 11 569 QUESTSTEP = 12 570 QUESTSTEPCOMPLETE = 13 571 EMBLEM = 14 572 QUEST = 15 573 SUBCLASS = 16 574 CLANBANNER = 17 575 AURA = 18 576 MOD = 19 577 DUMMY = 20 578 SHIP = 21 579 VEHICLE = 22 580 EMOTE = 23 581 GHOST = 24 582 PACKAGE = 25 583 BOUNTY = 26 584 WRAPPER = 27 585 SEASONALARTIFACT = 28 586 FINISHER = 29
Enums for Destiny2's item types.
713@typing.final 714class MembershipOption(int, Enum): 715 """A enum for GroupV2 membership options.""" 716 717 REVIEWD = 0 718 OPEN = 1 719 CLOSED = 2
A enum for GroupV2 membership options.
463@typing.final 464class MembershipType(int, Enum): 465 """An Enum for Bungie membership types.""" 466 467 NONE = 0 468 XBOX = 1 469 PSN = 2 470 STEAM = 3 471 BLIZZARD = 4 472 STADIA = 5 473 BUNGIE = 254 474 ALL = -1
An Enum for Bungie membership types.
163@attrs.define(auto_exc=True) 164class MembershipTypeError(BadRequest): 165 """A bad request error raised when passing wrong membership to the request. 166 167 Those fields are useful since it returns the correct membership and id which can be used 168 to make the request again with those fields. 169 """ 170 171 membership_type: str = attrs.field(default="") 172 """The errored membership type passed to the request.""" 173 174 membership_id: int = attrs.field(default=0) 175 """The errored user's membership id.""" 176 177 required_membership: str = attrs.field(default="") 178 """The required correct membership for errored user.""" 179 180 def __str__(self) -> str: 181 return ( 182 f"Expected membership: {self.required_membership}, " 183 f"But got {self.membership_type} for id {self.membership_id}" 184 ) 185 186 def __int__(self) -> int: 187 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
506@typing.final 507class MilestoneType(int, Enum): 508 """An Enum for Destiny 2 milestone types.""" 509 510 UNKNOWN = 0 511 TUTORIAL = 1 512 ONETIME = 2 513 WEEKLY = 3 514 DAILY = 4 515 SPECIAL = 5
An Enum for Destiny 2 milestone types.
129@attrs.define(auto_exc=True) 130class NotFound(HTTPException): 131 """Raised when an unknown request was not found.""" 132 133 http_status: http.HTTPStatus = attrs.field( 134 default=http.HTTPStatus.NOT_FOUND, init=False 135 )
Raised when an unknown request was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
235@typing.final 236class Place(int, Enum): 237 """An Enum for Destiny 2 Places and NOT Planets""" 238 239 ORBIT = 2961497387 240 SOCIAL = 4151112093 241 LIGHT_HOUSE = 4276116472 242 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
200@typing.final 201class Planet(int, Enum): 202 """An Enum for all available planets in Destiny 2.""" 203 204 UNKNOWN = 0 205 """Unknown space""" 206 207 EARTH = 3747705955 208 """Earth""" 209 210 DREAMING_CITY = 2877881518 211 """The Dreaming city.""" 212 213 NESSUS = 3526908984 214 """Nessus""" 215 216 MOON = 3325508439 217 """The Moon""" 218 219 COSMODROME = 3990611421 220 """The Cosmodrome""" 221 222 TANGLED_SHORE = 3821439926 223 """The Tangled Shore""" 224 225 VENUS = 3871070152 226 """Venus""" 227 228 EAZ = 541863059 # Exclusive event. 229 """European Aerial Zone""" 230 231 EUROPA = 1729879943 232 """Europa"""
An Enum for all available planets in Destiny 2.
683@typing.final 684class Presence(int, Enum): 685 """An enum for a bungie friend status.""" 686 687 OFFLINE_OR_UNKNOWN = 0 688 ONLINE = 1
An enum for a bungie friend status.
771@typing.final 772class PrivacySetting(int, Enum): 773 """An enum for players's privacy settings.""" 774 775 OPEN = 0 776 CLAN_AND_FRIENDS = 1 777 FRIENDS_ONLY = 2 778 INVITE_ONLY = 3 779 CLOSED = 4
An enum for players's privacy settings.
364class RESTClient(interfaces.RESTInterface): 365 """A RESTful client implementation for Bungie's API. 366 367 This client is designed to only make HTTP requests and return JSON objects 368 to provide RESTful functionality. 369 370 This client is also used within `aiobungie.Client` which deserialize those returned JSON objects 371 using the factory into Pythonic data classes objects which provide Python functionality. 372 373 Example 374 ------- 375 ```py 376 import aiobungie 377 378 async def main(): 379 async with aiobungie.RESTClient("TOKEN") as rest_client: 380 req = await rest_client.fetch_clan_members(4389205) 381 clan_members = req['results'] 382 for member in clan_members: 383 for k, v in member['destinyUserInfo'].items(): 384 print(k, v) 385 ``` 386 387 Parameters 388 ---------- 389 token : `str` 390 A valid application token from Bungie's developer portal. 391 392 Other Parameters 393 ---------------- 394 max_retries : `int` 395 The max retries number to retry if the request hit a `5xx` status code. 396 max_ratelimit_retries : `int` 397 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 398 client_secret : `typing.Optional[str]` 399 An optional application client secret, 400 This is only needed if you're fetching OAuth2 tokens with this client. 401 client_id : `typing.Optional[int]` 402 An optional application client id, 403 This is only needed if you're fetching OAuth2 tokens with this client. 404 enable_debugging : `bool | str` 405 Whether to enable logging responses or not. 406 407 Logging Levels 408 -------------- 409 * `False`: This will disable logging. 410 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 411 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 412 """ 413 414 __slots__ = ( 415 "_token", 416 "_session", 417 "_lock", 418 "_max_retries", 419 "_client_secret", 420 "_client_id", 421 "_metadata", 422 "_max_rate_limit_retries", 423 ) 424 425 def __init__( 426 self, 427 token: str, 428 /, 429 client_secret: typing.Optional[str] = None, 430 client_id: typing.Optional[int] = None, 431 *, 432 max_retries: int = 4, 433 max_ratelimit_retries: int = 3, 434 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 435 ) -> None: 436 self._session: typing.Optional[_Session] = None 437 self._lock: typing.Optional[asyncio.Lock] = None 438 self._client_secret = client_secret 439 self._client_id = client_id 440 self._token: str = token 441 self._max_retries = max_retries 442 self._max_rate_limit_retries = max_ratelimit_retries 443 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 444 445 self._set_debug_level(enable_debugging) 446 447 @property 448 def client_id(self) -> typing.Optional[int]: 449 return self._client_id 450 451 @property 452 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 453 return self._metadata 454 455 @property 456 def is_alive(self) -> bool: 457 return self._session is not None 458 459 @typing.final 460 async def close(self) -> None: 461 session = self._get_session() 462 await session.close() 463 self._session = None 464 465 @typing.final 466 def open(self) -> None: 467 """Open a new client session. This is called internally with contextmanager usage.""" 468 if self.is_alive: 469 raise RuntimeError("Cannot open a new session while it's already open.") 470 471 self._session = _Session.create( 472 owner=False, 473 raise_status=False, 474 connect=None, 475 socket_read=None, 476 socket_connect=None, 477 ) 478 479 @typing.final 480 def enable_debugging( 481 self, 482 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 483 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 484 /, 485 ) -> None: 486 self._set_debug_level(level, file) 487 488 @typing.final 489 async def static_request( 490 self, 491 method: typing.Union[RequestMethod, str], 492 path: str, 493 *, 494 auth: typing.Optional[str] = None, 495 json: typing.Optional[dict[str, typing.Any]] = None, 496 ) -> ResponseSig: 497 return await self._request(method, path, auth=auth, json=json) 498 499 @typing.final 500 def build_oauth2_url( 501 self, client_id: typing.Optional[int] = None 502 ) -> typing.Optional[str]: 503 client_id = client_id or self._client_id 504 if client_id is None: 505 return None 506 507 return url.OAUTH2_EP_BUILDER.format( 508 oauth_endpoint=url.OAUTH_EP, 509 client_id=client_id, 510 uuid=_uuid(), 511 ) 512 513 @staticmethod 514 def _set_debug_level( 515 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 516 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 517 ) -> None: 518 519 file_handler = logging.FileHandler(file, mode="w") if file else None 520 if level == "TRACE" or level == TRACE: 521 logging.basicConfig( 522 level=TRACE, handlers=[file_handler] if file_handler else None 523 ) 524 525 elif level: 526 logging.basicConfig( 527 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 528 ) 529 530 def _get_session(self) -> _Session: 531 if self._session: 532 return self._session 533 534 raise RuntimeError( 535 "Cannot return a session while its close. Make sure you use `async with` before making requests." 536 ) 537 538 async def _request( 539 self, 540 method: typing.Union[RequestMethod, str], 541 route: str, 542 *, 543 base: bool = False, 544 oauth2: bool = False, 545 auth: typing.Optional[str] = None, 546 unwrapping: typing.Literal["json", "read"] = "json", 547 json: typing.Optional[dict[str, typing.Any]] = None, 548 headers: typing.Optional[dict[str, typing.Any]] = None, 549 data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None, 550 ) -> ResponseSig: 551 552 retries: int = 0 553 session = self._get_session() 554 headers = headers or {} 555 556 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 557 headers["X-API-KEY"] = self._token 558 559 if auth is not None: 560 headers[_AUTH_HEADER] = f"Bearer {auth}" 561 562 # Handling endpoints 563 endpoint = url.BASE 564 565 if not base: 566 endpoint = endpoint + url.REST_EP 567 568 if oauth2: 569 headers["Content-Type"] = "application/x-www-form-urlencoded" 570 endpoint = endpoint + url.TOKEN_EP 571 572 if self._lock is None: 573 self._lock = asyncio.Lock() 574 575 while True: 576 try: 577 async with (stack := contextlib.AsyncExitStack()): 578 await stack.enter_async_context(self._lock) 579 580 # We make the request here. 581 taken_time = time.monotonic() 582 response = await stack.enter_async_context( 583 session.client_session.request( 584 method=method, 585 url=f"{endpoint}/{route}", 586 json=json, 587 headers=headers, 588 data=data, 589 ) 590 ) 591 response_time = (time.monotonic() - taken_time) * 1_000 592 593 _LOG.debug( 594 "%s %s %s Time %.4fms", 595 method, 596 f"{endpoint}/{route}", 597 f"{response.status} {response.reason}", 598 response_time, 599 ) 600 601 await self._handle_ratelimit( 602 response, method, route, self._max_rate_limit_retries 603 ) 604 605 if response.status == http.HTTPStatus.NO_CONTENT: 606 return None 607 608 if 300 > response.status >= 200: 609 if unwrapping == "read": 610 # We need to read the bytes for the manifest response. 611 return await response.read() 612 613 if response.content_type == _APP_JSON: 614 json_data = await response.json() 615 616 _LOG.debug( 617 "%s %s %s Time %.4fms", 618 method, 619 f"{endpoint}/{route}", 620 f"{response.status} {response.reason}", 621 response_time, 622 ) 623 624 if _LOG.isEnabledFor(TRACE): 625 headers.update(response.headers) # type: ignore 626 627 _LOG.log( 628 TRACE, 629 "%s", 630 error.stringify_http_message(headers), 631 ) 632 633 # Return the response. 634 # oauth2 responses are not packed inside a Response object. 635 if oauth2: 636 return json_data # type: ignore[no-any-return] 637 638 return json_data["Response"] # type: ignore[no-any-return] 639 640 if ( 641 response.status in _RETRY_5XX 642 and retries < self._max_retries # noqa: W503 643 ): 644 backoff_ = backoff.ExponentialBackOff(maximum=6) 645 sleep_time = next(backoff_) 646 _LOG.warning( 647 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 648 response.status, 649 response.reason, 650 sleep_time, 651 self._max_retries - retries, 652 ) 653 654 retries += 1 655 await asyncio.sleep(sleep_time) 656 continue 657 658 raise await error.raise_error(response) 659 # eol 660 except _Dyn: 661 continue 662 663 if not typing.TYPE_CHECKING: 664 665 def __enter__(self) -> typing.NoReturn: 666 cls = type(self) 667 raise TypeError( 668 f"{cls.__qualname__} is async only, use 'async with' instead." 669 ) 670 671 def __exit__( 672 self, 673 exception_type: typing.Optional[type[BaseException]], 674 exception: typing.Optional[BaseException], 675 exception_traceback: typing.Optional[types.TracebackType], 676 ) -> None: 677 ... 678 679 async def __aenter__(self) -> RESTClient: 680 self.open() 681 return self 682 683 async def __aexit__( 684 self, 685 exception_type: typing.Optional[type[BaseException]], 686 exception: typing.Optional[BaseException], 687 exception_traceback: typing.Optional[types.TracebackType], 688 ) -> None: 689 await self.close() 690 691 # We don't want this to be super complicated. 692 @staticmethod 693 @typing.final 694 async def _handle_ratelimit( 695 response: aiohttp.ClientResponse, 696 method: str, 697 route: str, 698 max_ratelimit_retries: int = 3, 699 ) -> None: 700 701 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 702 return 703 704 if response.content_type != _APP_JSON: 705 raise error.HTTPError( 706 f"Being ratelimited on non JSON request, {response.content_type}.", 707 http.HTTPStatus.TOO_MANY_REQUESTS, 708 ) 709 710 count: int = 0 711 json: typedefs.JSONObject = await response.json() 712 retry_after = float(json["ThrottleSeconds"]) 713 714 while True: 715 if count == max_ratelimit_retries: 716 raise _Dyn 717 718 if retry_after <= 0: 719 # We sleep for a little bit to avoid funky behavior. 720 sleep_time = float(random.random() + 0.93) / 2 721 722 _LOG.warning( 723 "We're being ratelimited with method %s route %s. Sleeping for %.2fs.", 724 method, 725 route, 726 sleep_time, 727 ) 728 count += 1 729 await asyncio.sleep(sleep_time) 730 continue 731 732 raise error.RateLimitedError( 733 body=json, 734 url=str(response.real_url), 735 retry_after=retry_after, 736 ) 737 738 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 739 740 if not isinstance(self._client_id, int): 741 raise TypeError( 742 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 743 ) 744 745 if not isinstance(self._client_secret, str): 746 raise TypeError( 747 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 748 ) 749 750 headers = { 751 "client_secret": self._client_secret, 752 } 753 754 data = ( 755 f"grant_type=authorization_code&code={code}" 756 f"&client_id={self._client_id}&client_secret={self._client_secret}" 757 ) 758 759 response = await self._request( 760 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 761 ) 762 assert isinstance(response, dict) 763 return builders.OAuth2Response.build_response(response) 764 765 async def refresh_access_token( 766 self, refresh_token: str, / 767 ) -> builders.OAuth2Response: 768 if not isinstance(self._client_id, int): 769 raise TypeError( 770 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 771 ) 772 773 if not isinstance(self._client_secret, str): 774 raise TypeError( 775 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 776 ) 777 778 data = { 779 "grant_type": "refresh_token", 780 "refresh_token": refresh_token, 781 "client_id": self._client_id, 782 "client_secret": self._client_secret, 783 "Content-Type": "application/x-www-form-urlencoded", 784 } 785 786 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 787 assert isinstance(response, dict) 788 return builders.OAuth2Response.build_response(response) 789 790 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 791 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 792 resp = await self._request( 793 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 794 ) 795 assert isinstance(resp, dict) 796 return resp 797 798 async def fetch_user_themes(self) -> typedefs.JSONArray: 799 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 800 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 801 assert isinstance(resp, list) 802 return resp 803 804 async def fetch_membership_from_id( 805 self, 806 id: int, 807 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 808 /, 809 ) -> typedefs.JSONObject: 810 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 811 resp = await self._request( 812 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 813 ) 814 assert isinstance(resp, dict) 815 return resp 816 817 async def fetch_player( 818 self, 819 name: str, 820 code: int, 821 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 822 /, 823 ) -> typedefs.JSONArray: 824 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 825 resp = await self._request( 826 RequestMethod.POST, 827 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 828 json={"displayName": name, "displayNameCode": code}, 829 ) 830 assert isinstance(resp, list) 831 return resp 832 833 async def search_users(self, name: str, /) -> typedefs.JSONObject: 834 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 835 resp = await self._request( 836 RequestMethod.POST, 837 "User/Search/GlobalName/0", 838 json={"displayNamePrefix": name}, 839 ) 840 assert isinstance(resp, dict) 841 return resp 842 843 async def fetch_clan_from_id( 844 self, id: int, /, access_token: typing.Optional[str] = None 845 ) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 849 ) 850 assert isinstance(resp, dict) 851 return resp 852 853 async def fetch_clan( 854 self, 855 name: str, 856 /, 857 access_token: typing.Optional[str] = None, 858 *, 859 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 860 ) -> typedefs.JSONObject: 861 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 862 resp = await self._request( 863 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 864 ) 865 assert isinstance(resp, dict) 866 return resp 867 868 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 869 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 870 resp = await self._request( 871 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 872 ) 873 assert isinstance(resp, dict) 874 return resp 875 876 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 877 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 878 resp = await self._request( 879 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 880 ) 881 assert isinstance(resp, list) 882 return resp 883 884 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 885 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 886 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 887 assert isinstance(resp, dict) 888 return resp 889 890 async def fetch_character( 891 self, 892 member_id: int, 893 membership_type: typedefs.IntAnd[enums.MembershipType], 894 character_id: int, 895 components: list[enums.ComponentType], 896 auth: typing.Optional[str] = None, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 collector = _collect_components(components) 900 response = await self._request( 901 RequestMethod.GET, 902 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 903 f"Character/{character_id}/?components={collector}", 904 auth=auth, 905 ) 906 assert isinstance(response, dict) 907 return response 908 909 async def fetch_activities( 910 self, 911 member_id: int, 912 character_id: int, 913 mode: typedefs.IntAnd[enums.GameMode], 914 membership_type: typedefs.IntAnd[ 915 enums.MembershipType 916 ] = enums.MembershipType.ALL, 917 *, 918 page: int = 0, 919 limit: int = 1, 920 ) -> typedefs.JSONObject: 921 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 922 resp = await self._request( 923 RequestMethod.GET, 924 f"Destiny2/{int(membership_type)}/Account/" 925 f"{member_id}/Character/{character_id}/Stats/Activities" 926 f"/?mode={int(mode)}&count={limit}&page={page}", 927 ) 928 assert isinstance(resp, dict) 929 return resp 930 931 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 932 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 933 resp = await self._request( 934 RequestMethod.GET, 935 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 936 ) 937 assert isinstance(resp, dict) 938 return resp 939 940 async def fetch_profile( 941 self, 942 membership_id: int, 943 type: typedefs.IntAnd[enums.MembershipType], 944 components: list[enums.ComponentType], 945 auth: typing.Optional[str] = None, 946 ) -> typedefs.JSONObject: 947 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 948 collector = _collect_components(components) 949 response = await self._request( 950 RequestMethod.GET, 951 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 952 auth=auth, 953 ) 954 assert isinstance(response, dict) 955 return response 956 957 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 958 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 959 response = await self._request( 960 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 961 ) 962 assert isinstance(response, dict) 963 return response 964 965 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 966 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 967 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 968 assert isinstance(resp, dict) 969 return resp 970 971 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 972 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 973 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 974 assert isinstance(resp, dict) 975 return resp 976 977 async def fetch_groups_for_member( 978 self, 979 member_id: int, 980 member_type: typedefs.IntAnd[enums.MembershipType], 981 /, 982 *, 983 filter: int = 0, 984 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 985 ) -> typedefs.JSONObject: 986 resp = await self._request( 987 RequestMethod.GET, 988 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 989 ) 990 assert isinstance(resp, dict) 991 return resp 992 993 async def fetch_potential_groups_for_member( 994 self, 995 member_id: int, 996 member_type: typedefs.IntAnd[enums.MembershipType], 997 /, 998 *, 999 filter: int = 0, 1000 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 1001 ) -> typedefs.JSONObject: 1002 resp = await self._request( 1003 RequestMethod.GET, 1004 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 1005 ) 1006 assert isinstance(resp, dict) 1007 return resp 1008 1009 async def fetch_clan_members( 1010 self, 1011 clan_id: int, 1012 /, 1013 *, 1014 name: typing.Optional[str] = None, 1015 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 1016 ) -> typedefs.JSONObject: 1017 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1018 resp = await self._request( 1019 RequestMethod.GET, 1020 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1021 ) 1022 assert isinstance(resp, dict) 1023 return resp 1024 1025 async def fetch_hardlinked_credentials( 1026 self, 1027 credential: int, 1028 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1029 /, 1030 ) -> typedefs.JSONObject: 1031 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1032 resp = await self._request( 1033 RequestMethod.GET, 1034 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1035 ) 1036 assert isinstance(resp, dict) 1037 return resp 1038 1039 async def fetch_user_credentials( 1040 self, access_token: str, membership_id: int, / 1041 ) -> typedefs.JSONArray: 1042 resp = await self._request( 1043 RequestMethod.GET, 1044 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1045 auth=access_token, 1046 ) 1047 assert isinstance(resp, list) 1048 return resp 1049 1050 async def insert_socket_plug( 1051 self, 1052 action_token: str, 1053 /, 1054 instance_id: int, 1055 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1056 character_id: int, 1057 membership_type: typedefs.IntAnd[enums.MembershipType], 1058 ) -> typedefs.JSONObject: 1059 1060 if isinstance(plug, builders.PlugSocketBuilder): 1061 plug = plug.collect() 1062 1063 body = { 1064 "actionToken": action_token, 1065 "itemInstanceId": instance_id, 1066 "plug": plug, 1067 "characterId": character_id, 1068 "membershipType": int(membership_type), 1069 } 1070 resp = await self._request( 1071 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1072 ) 1073 assert isinstance(resp, dict) 1074 return resp 1075 1076 async def insert_socket_plug_free( 1077 self, 1078 access_token: str, 1079 /, 1080 instance_id: int, 1081 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1082 character_id: int, 1083 membership_type: typedefs.IntAnd[enums.MembershipType], 1084 ) -> typedefs.JSONObject: 1085 1086 if isinstance(plug, builders.PlugSocketBuilder): 1087 plug = plug.collect() 1088 1089 body = { 1090 "itemInstanceId": instance_id, 1091 "plug": plug, 1092 "characterId": character_id, 1093 "membershipType": int(membership_type), 1094 } 1095 resp = await self._request( 1096 RequestMethod.POST, 1097 "Destiny2/Actions/Items/InsertSocketPlugFree", 1098 json=body, 1099 auth=access_token, 1100 ) 1101 assert isinstance(resp, dict) 1102 return resp 1103 1104 async def set_item_lock_state( 1105 self, 1106 access_token: str, 1107 state: bool, 1108 /, 1109 item_id: int, 1110 character_id: int, 1111 membership_type: typedefs.IntAnd[enums.MembershipType], 1112 ) -> int: 1113 body = { 1114 "state": state, 1115 "itemId": item_id, 1116 "characterId": character_id, 1117 "membership_type": int(membership_type), 1118 } 1119 response = await self._request( 1120 RequestMethod.POST, 1121 "Destiny2/Actions/Items/SetLockState", 1122 json=body, 1123 auth=access_token, 1124 ) 1125 assert isinstance(response, int) 1126 return response 1127 1128 async def set_quest_track_state( 1129 self, 1130 access_token: str, 1131 state: bool, 1132 /, 1133 item_id: int, 1134 character_id: int, 1135 membership_type: typedefs.IntAnd[enums.MembershipType], 1136 ) -> int: 1137 body = { 1138 "state": state, 1139 "itemId": item_id, 1140 "characterId": character_id, 1141 "membership_type": int(membership_type), 1142 } 1143 response = await self._request( 1144 RequestMethod.POST, 1145 "Destiny2/Actions/Items/SetTrackedState", 1146 json=body, 1147 auth=access_token, 1148 ) 1149 assert isinstance(response, int) 1150 return response 1151 1152 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1153 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1154 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1155 assert isinstance(path, dict) 1156 return path 1157 1158 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1159 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1160 _ensure_manifest_language(language) 1161 1162 content = await self.fetch_manifest_path() 1163 resp = await self._request( 1164 RequestMethod.GET, 1165 content["mobileWorldContentPaths"][language], 1166 unwrapping="read", 1167 base=True, 1168 ) 1169 assert isinstance(resp, bytes) 1170 return resp 1171 1172 async def download_manifest( 1173 self, 1174 language: str = "en", 1175 name: str = "manifest", 1176 path: typing.Union[pathlib.Path, str] = ".", 1177 *, 1178 force: bool = False, 1179 ) -> None: 1180 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1181 complete_path = _get_path(name, path, sql=True) 1182 1183 if complete_path.exists() and force: 1184 if force: 1185 _LOG.info( 1186 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1187 ) 1188 complete_path.unlink(missing_ok=True) 1189 1190 return await self.download_manifest(language, name, path, force=force) 1191 1192 else: 1193 raise FileExistsError( 1194 "Manifest file already exists, " 1195 "To force download, set the `force` parameter to `True`." 1196 ) 1197 1198 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1199 data_bytes = await self.read_manifest_bytes(language) 1200 await asyncio.get_running_loop().run_in_executor( 1201 None, _write_sqlite_bytes, data_bytes, path, name 1202 ) 1203 1204 async def download_json_manifest( 1205 self, 1206 file_name: str = "manifest", 1207 path: typing.Union[str, pathlib.Path] = ".", 1208 language: str = "en", 1209 ) -> None: 1210 _ensure_manifest_language(language) 1211 1212 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1213 1214 content = await self.fetch_manifest_path() 1215 json_bytes = await self._request( 1216 RequestMethod.GET, 1217 content["jsonWorldContentPaths"][language], 1218 unwrapping="read", 1219 base=True, 1220 ) 1221 1222 await asyncio.get_running_loop().run_in_executor( 1223 None, _write_json_bytes, json_bytes, file_name, path 1224 ) 1225 _LOG.info("Finished downloading manifest JSON.") 1226 1227 async def fetch_manifest_version(self) -> str: 1228 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1229 1230 async def fetch_linked_profiles( 1231 self, 1232 member_id: int, 1233 member_type: typedefs.IntAnd[enums.MembershipType], 1234 /, 1235 *, 1236 all: bool = False, 1237 ) -> typedefs.JSONObject: 1238 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1239 resp = await self._request( 1240 RequestMethod.GET, 1241 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1242 ) 1243 assert isinstance(resp, dict) 1244 return resp 1245 1246 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1247 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1248 resp = await self._request( 1249 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1250 ) 1251 assert isinstance(resp, dict) 1252 return resp 1253 1254 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1257 assert isinstance(resp, dict) 1258 return resp 1259 1260 async def fetch_public_milestone_content( 1261 self, milestone_hash: int, / 1262 ) -> typedefs.JSONObject: 1263 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1264 resp = await self._request( 1265 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1266 ) 1267 assert isinstance(resp, dict) 1268 return resp 1269 1270 async def fetch_current_user_memberships( 1271 self, access_token: str, / 1272 ) -> typedefs.JSONObject: 1273 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1274 resp = await self._request( 1275 RequestMethod.GET, 1276 "User/GetMembershipsForCurrentUser/", 1277 auth=access_token, 1278 ) 1279 assert isinstance(resp, dict) 1280 return resp 1281 1282 async def equip_item( 1283 self, 1284 access_token: str, 1285 /, 1286 item_id: int, 1287 character_id: int, 1288 membership_type: typedefs.IntAnd[enums.MembershipType], 1289 ) -> None: 1290 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1291 payload = { 1292 "itemId": item_id, 1293 "characterId": character_id, 1294 "membershipType": int(membership_type), 1295 } 1296 1297 await self._request( 1298 RequestMethod.POST, 1299 "Destiny2/Actions/Items/EquipItem/", 1300 json=payload, 1301 auth=access_token, 1302 ) 1303 1304 async def equip_items( 1305 self, 1306 access_token: str, 1307 /, 1308 item_ids: list[int], 1309 character_id: int, 1310 membership_type: typedefs.IntAnd[enums.MembershipType], 1311 ) -> None: 1312 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1313 payload = { 1314 "itemIds": item_ids, 1315 "characterId": character_id, 1316 "membershipType": int(membership_type), 1317 } 1318 await self._request( 1319 RequestMethod.POST, 1320 "Destiny2/Actions/Items/EquipItems/", 1321 json=payload, 1322 auth=access_token, 1323 ) 1324 1325 async def ban_clan_member( 1326 self, 1327 access_token: str, 1328 /, 1329 group_id: int, 1330 membership_id: int, 1331 membership_type: typedefs.IntAnd[enums.MembershipType], 1332 *, 1333 length: int = 0, 1334 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1335 ) -> None: 1336 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1337 payload = {"comment": str(comment), "length": length} 1338 await self._request( 1339 RequestMethod.POST, 1340 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1341 json=payload, 1342 auth=access_token, 1343 ) 1344 1345 async def unban_clan_member( 1346 self, 1347 access_token: str, 1348 /, 1349 group_id: int, 1350 membership_id: int, 1351 membership_type: typedefs.IntAnd[enums.MembershipType], 1352 ) -> None: 1353 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1354 await self._request( 1355 RequestMethod.POST, 1356 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1357 auth=access_token, 1358 ) 1359 1360 async def kick_clan_member( 1361 self, 1362 access_token: str, 1363 /, 1364 group_id: int, 1365 membership_id: int, 1366 membership_type: typedefs.IntAnd[enums.MembershipType], 1367 ) -> typedefs.JSONObject: 1368 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1369 resp = await self._request( 1370 RequestMethod.POST, 1371 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1372 auth=access_token, 1373 ) 1374 assert isinstance(resp, dict) 1375 return resp 1376 1377 async def edit_clan( 1378 self, 1379 access_token: str, 1380 /, 1381 group_id: int, 1382 *, 1383 name: typedefs.NoneOr[str] = None, 1384 about: typedefs.NoneOr[str] = None, 1385 motto: typedefs.NoneOr[str] = None, 1386 theme: typedefs.NoneOr[str] = None, 1387 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1388 is_public: typedefs.NoneOr[bool] = None, 1389 locale: typedefs.NoneOr[str] = None, 1390 avatar_image_index: typedefs.NoneOr[int] = None, 1391 membership_option: typedefs.NoneOr[ 1392 typedefs.IntAnd[enums.MembershipOption] 1393 ] = None, 1394 allow_chat: typedefs.NoneOr[bool] = None, 1395 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1396 call_sign: typedefs.NoneOr[str] = None, 1397 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1398 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1399 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1400 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1401 ) -> None: 1402 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1403 payload = { 1404 "name": name, 1405 "about": about, 1406 "motto": motto, 1407 "theme": theme, 1408 "tags": tags, 1409 "isPublic": is_public, 1410 "avatarImageIndex": avatar_image_index, 1411 "isPublicTopicAdminOnly": is_public_topic_admin, 1412 "allowChat": allow_chat, 1413 "chatSecurity": chat_security, 1414 "callsign": call_sign, 1415 "homepage": homepage, 1416 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1417 "defaultPublicity": default_publicity, 1418 "locale": locale, 1419 } 1420 if membership_option is not None: 1421 payload["membershipOption"] = int(membership_option) 1422 1423 await self._request( 1424 RequestMethod.POST, 1425 f"GroupV2/{group_id}/Edit", 1426 json=payload, 1427 auth=access_token, 1428 ) 1429 1430 async def edit_clan_options( 1431 self, 1432 access_token: str, 1433 /, 1434 group_id: int, 1435 *, 1436 invite_permissions_override: typedefs.NoneOr[bool] = None, 1437 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1438 host_guided_game_permission_override: typedefs.NoneOr[ 1439 typing.Literal[0, 1, 2] 1440 ] = None, 1441 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1442 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1443 ) -> None: 1444 1445 payload = { 1446 "InvitePermissionOverride": invite_permissions_override, 1447 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1448 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1449 "UpdateBannerPermissionOverride": update_banner_permission_override, 1450 "JoinLevel": int(join_level) if join_level else None, 1451 } 1452 1453 await self._request( 1454 RequestMethod.POST, 1455 f"GroupV2/{group_id}/EditFounderOptions", 1456 json=payload, 1457 auth=access_token, 1458 ) 1459 1460 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1461 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1462 resp = await self._request( 1463 RequestMethod.GET, 1464 "Social/Friends/", 1465 auth=access_token, 1466 ) 1467 assert isinstance(resp, dict) 1468 return resp 1469 1470 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 resp = await self._request( 1473 RequestMethod.GET, 1474 "Social/Friends/Requests", 1475 auth=access_token, 1476 ) 1477 assert isinstance(resp, dict) 1478 return resp 1479 1480 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Accept/{member_id}", 1485 auth=access_token, 1486 ) 1487 1488 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Add/{member_id}", 1493 auth=access_token, 1494 ) 1495 1496 async def decline_friend_request( 1497 self, access_token: str, /, member_id: int 1498 ) -> None: 1499 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1500 await self._request( 1501 RequestMethod.POST, 1502 f"Social/Friends/Requests/Decline/{member_id}", 1503 auth=access_token, 1504 ) 1505 1506 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1507 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1508 await self._request( 1509 RequestMethod.POST, 1510 f"Social/Friends/Remove/{member_id}", 1511 auth=access_token, 1512 ) 1513 1514 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1515 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1516 await self._request( 1517 RequestMethod.POST, 1518 f"Social/Friends/Requests/Remove/{member_id}", 1519 auth=access_token, 1520 ) 1521 1522 async def approve_all_pending_group_users( 1523 self, 1524 access_token: str, 1525 /, 1526 group_id: int, 1527 message: undefined.UndefinedOr[str] = undefined.Undefined, 1528 ) -> None: 1529 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1530 await self._request( 1531 RequestMethod.POST, 1532 f"GroupV2/{group_id}/Members/ApproveAll", 1533 auth=access_token, 1534 json={"message": str(message)}, 1535 ) 1536 1537 async def deny_all_pending_group_users( 1538 self, 1539 access_token: str, 1540 /, 1541 group_id: int, 1542 *, 1543 message: undefined.UndefinedOr[str] = undefined.Undefined, 1544 ) -> None: 1545 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/Members/DenyAll", 1549 auth=access_token, 1550 json={"message": str(message)}, 1551 ) 1552 1553 async def add_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 *, 1559 name: undefined.UndefinedOr[str] = undefined.Undefined, 1560 security: typing.Literal[0, 1] = 0, 1561 ) -> None: 1562 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1563 payload = {"chatName": str(name), "chatSecurity": security} 1564 await self._request( 1565 RequestMethod.POST, 1566 f"GroupV2/{group_id}/OptionalConversations/Add", 1567 json=payload, 1568 auth=access_token, 1569 ) 1570 1571 async def edit_optional_conversation( 1572 self, 1573 access_token: str, 1574 /, 1575 group_id: int, 1576 conversation_id: int, 1577 *, 1578 name: undefined.UndefinedOr[str] = undefined.Undefined, 1579 security: typing.Literal[0, 1] = 0, 1580 enable_chat: bool = False, 1581 ) -> None: 1582 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1583 payload = { 1584 "chatEnabled": enable_chat, 1585 "chatName": str(name), 1586 "chatSecurity": security, 1587 } 1588 await self._request( 1589 RequestMethod.POST, 1590 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1591 json=payload, 1592 auth=access_token, 1593 ) 1594 1595 async def transfer_item( 1596 self, 1597 access_token: str, 1598 /, 1599 item_id: int, 1600 item_hash: int, 1601 character_id: int, 1602 member_type: typedefs.IntAnd[enums.MembershipType], 1603 *, 1604 stack_size: int = 1, 1605 vault: bool = False, 1606 ) -> None: 1607 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1608 payload = { 1609 "characterId": character_id, 1610 "membershipType": int(member_type), 1611 "itemId": item_id, 1612 "itemReferenceHash": item_hash, 1613 "stackSize": stack_size, 1614 "transferToVault": vault, 1615 } 1616 await self._request( 1617 RequestMethod.POST, 1618 "Destiny2/Actions/Items/TransferItem", 1619 json=payload, 1620 auth=access_token, 1621 ) 1622 1623 async def pull_item( 1624 self, 1625 access_token: str, 1626 /, 1627 item_id: int, 1628 item_hash: int, 1629 character_id: int, 1630 member_type: typedefs.IntAnd[enums.MembershipType], 1631 *, 1632 stack_size: int = 1, 1633 vault: bool = False, 1634 ) -> None: 1635 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1636 payload = { 1637 "characterId": character_id, 1638 "membershipType": int(member_type), 1639 "itemId": item_id, 1640 "itemReferenceHash": item_hash, 1641 "stackSize": stack_size, 1642 "transferToVault": vault, 1643 } 1644 await self._request( 1645 RequestMethod.POST, 1646 "Destiny2/Actions/Items/PullFromPostmaster", 1647 json=payload, 1648 auth=access_token, 1649 ) 1650 1651 async def fetch_fireteams( 1652 self, 1653 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1654 *, 1655 platform: typedefs.IntAnd[ 1656 fireteams.FireteamPlatform 1657 ] = fireteams.FireteamPlatform.ANY, 1658 language: typing.Union[ 1659 fireteams.FireteamLanguage, str 1660 ] = fireteams.FireteamLanguage.ALL, 1661 date_range: typedefs.IntAnd[ 1662 fireteams.FireteamDate 1663 ] = fireteams.FireteamDate.ALL, 1664 page: int = 0, 1665 slots_filter: int = 0, 1666 ) -> typedefs.JSONObject: 1667 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1668 resp = await self._request( 1669 RequestMethod.GET, 1670 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1671 ) 1672 assert isinstance(resp, dict) 1673 return resp 1674 1675 async def fetch_avaliable_clan_fireteams( 1676 self, 1677 access_token: str, 1678 group_id: int, 1679 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1680 *, 1681 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1682 language: typing.Union[fireteams.FireteamLanguage, str], 1683 date_range: typedefs.IntAnd[ 1684 fireteams.FireteamDate 1685 ] = fireteams.FireteamDate.ALL, 1686 page: int = 0, 1687 public_only: bool = False, 1688 slots_filter: int = 0, 1689 ) -> typedefs.JSONObject: 1690 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1691 resp = await self._request( 1692 RequestMethod.GET, 1693 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1694 json={"langFilter": str(language)}, 1695 auth=access_token, 1696 ) 1697 assert isinstance(resp, dict) 1698 return resp 1699 1700 async def fetch_clan_fireteam( 1701 self, access_token: str, fireteam_id: int, group_id: int 1702 ) -> typedefs.JSONObject: 1703 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1704 resp = await self._request( 1705 RequestMethod.GET, 1706 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1707 auth=access_token, 1708 ) 1709 assert isinstance(resp, dict) 1710 return resp 1711 1712 async def fetch_my_clan_fireteams( 1713 self, 1714 access_token: str, 1715 group_id: int, 1716 *, 1717 include_closed: bool = True, 1718 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1719 language: typing.Union[fireteams.FireteamLanguage, str], 1720 filtered: bool = True, 1721 page: int = 0, 1722 ) -> typedefs.JSONObject: 1723 payload = {"groupFilter": filtered, "langFilter": str(language)} 1724 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1725 resp = await self._request( 1726 RequestMethod.GET, 1727 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1728 json=payload, 1729 auth=access_token, 1730 ) 1731 assert isinstance(resp, dict) 1732 return resp 1733 1734 async def fetch_private_clan_fireteams( 1735 self, access_token: str, group_id: int, / 1736 ) -> int: 1737 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1738 resp = await self._request( 1739 RequestMethod.GET, 1740 f"Fireteam/Clan/{group_id}/ActiveCount", 1741 auth=access_token, 1742 ) 1743 assert isinstance(resp, int) 1744 return resp 1745 1746 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1747 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1748 resp = await self._request( 1749 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1750 ) 1751 assert isinstance(resp, dict) 1752 return resp 1753 1754 async def search_entities( 1755 self, name: str, entity_type: str, *, page: int = 0 1756 ) -> typedefs.JSONObject: 1757 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1758 resp = await self._request( 1759 RequestMethod.GET, 1760 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1761 json={"page": page}, 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp 1765 1766 async def fetch_unique_weapon_history( 1767 self, 1768 membership_id: int, 1769 character_id: int, 1770 membership_type: typedefs.IntAnd[enums.MembershipType], 1771 ) -> typedefs.JSONObject: 1772 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1773 resp = await self._request( 1774 RequestMethod.GET, 1775 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1776 ) 1777 assert isinstance(resp, dict) 1778 return resp 1779 1780 async def fetch_item( 1781 self, 1782 member_id: int, 1783 item_id: int, 1784 membership_type: typedefs.IntAnd[enums.MembershipType], 1785 components: list[enums.ComponentType], 1786 ) -> typedefs.JSONObject: 1787 collector = _collect_components(components) 1788 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1789 resp = await self._request( 1790 RequestMethod.GET, 1791 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1792 ) 1793 assert isinstance(resp, dict) 1794 return resp 1795 1796 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1797 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1798 resp = await self._request( 1799 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1800 ) 1801 assert isinstance(resp, dict) 1802 return resp 1803 1804 async def fetch_available_locales(self) -> typedefs.JSONObject: 1805 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1806 resp = await self._request( 1807 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1808 ) 1809 assert isinstance(resp, dict) 1810 return resp 1811 1812 async def fetch_common_settings(self) -> typedefs.JSONObject: 1813 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1814 resp = await self._request(RequestMethod.GET, "Settings") 1815 assert isinstance(resp, dict) 1816 return resp 1817 1818 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1819 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1820 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1821 assert isinstance(resp, dict) 1822 return resp 1823 1824 async def fetch_global_alerts( 1825 self, *, include_streaming: bool = False 1826 ) -> typedefs.JSONArray: 1827 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1828 resp = await self._request( 1829 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1830 ) 1831 assert isinstance(resp, list) 1832 return resp 1833 1834 async def awainitialize_request( 1835 self, 1836 access_token: str, 1837 type: typing.Literal[0, 1], 1838 membership_type: typedefs.IntAnd[enums.MembershipType], 1839 /, 1840 *, 1841 affected_item_id: typing.Optional[int] = None, 1842 character_id: typing.Optional[int] = None, 1843 ) -> typedefs.JSONObject: 1844 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1845 1846 body = {"type": type, "membershipType": int(membership_type)} 1847 1848 if affected_item_id is not None: 1849 body["affectedItemId"] = affected_item_id 1850 1851 if character_id is not None: 1852 body["characterId"] = character_id 1853 1854 resp = await self._request( 1855 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1856 ) 1857 assert isinstance(resp, dict) 1858 return resp 1859 1860 async def awaget_action_token( 1861 self, access_token: str, correlation_id: str, / 1862 ) -> typedefs.JSONObject: 1863 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1864 resp = await self._request( 1865 RequestMethod.POST, 1866 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1867 auth=access_token, 1868 ) 1869 assert isinstance(resp, dict) 1870 return resp 1871 1872 async def awa_provide_authorization_result( 1873 self, 1874 access_token: str, 1875 selection: int, 1876 correlation_id: str, 1877 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1878 ) -> int: 1879 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1880 1881 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1882 1883 resp = await self._request( 1884 RequestMethod.POST, 1885 "Destiny2/Awa/AwaProvideAuthorizationResult", 1886 json=body, 1887 auth=access_token, 1888 ) 1889 assert isinstance(resp, int) 1890 return resp 1891 1892 async def fetch_vendors( 1893 self, 1894 access_token: str, 1895 character_id: int, 1896 membership_id: int, 1897 membership_type: typedefs.IntAnd[enums.MembershipType], 1898 /, 1899 components: list[enums.ComponentType], 1900 filter: typing.Optional[int] = None, 1901 ) -> typedefs.JSONObject: 1902 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1903 components_ = _collect_components(components) 1904 route = ( 1905 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1906 f"/Character/{character_id}/Vendors/?components={components_}" 1907 ) 1908 1909 if filter is not None: 1910 route = route + f"&filter={filter}" 1911 1912 resp = await self._request( 1913 RequestMethod.GET, 1914 route, 1915 auth=access_token, 1916 ) 1917 assert isinstance(resp, dict) 1918 return resp 1919 1920 async def fetch_vendor( 1921 self, 1922 access_token: str, 1923 character_id: int, 1924 membership_id: int, 1925 membership_type: typedefs.IntAnd[enums.MembershipType], 1926 vendor_hash: int, 1927 /, 1928 components: list[enums.ComponentType], 1929 ) -> typedefs.JSONObject: 1930 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1931 components_ = _collect_components(components) 1932 resp = await self._request( 1933 RequestMethod.GET, 1934 ( 1935 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1936 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1937 ), 1938 auth=access_token, 1939 ) 1940 assert isinstance(resp, dict) 1941 return resp 1942 1943 async def fetch_application_api_usage( 1944 self, 1945 access_token: str, 1946 application_id: int, 1947 /, 1948 *, 1949 start: typing.Optional[datetime.datetime] = None, 1950 end: typing.Optional[datetime.datetime] = None, 1951 ) -> typedefs.JSONObject: 1952 1953 end_date, start_date = time.parse_date_range(end, start) 1954 resp = await self._request( 1955 RequestMethod.GET, 1956 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1957 auth=access_token, 1958 ) 1959 assert isinstance(resp, dict) 1960 return resp 1961 1962 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1963 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1964 assert isinstance(resp, list) 1965 return resp 1966 1967 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1968 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1969 assert isinstance(resp, dict) 1970 return resp 1971 1972 async def fetch_content_by_id( 1973 self, id: int, locale: str, /, *, head: bool = False 1974 ) -> typedefs.JSONObject: 1975 resp = await self._request( 1976 RequestMethod.GET, 1977 f"Content/GetContentById/{id}/{locale}/", 1978 json={"head": head}, 1979 ) 1980 assert isinstance(resp, dict) 1981 return resp 1982 1983 async def fetch_content_by_tag_and_type( 1984 self, locale: str, tag: str, type: str, *, head: bool = False 1985 ) -> typedefs.JSONObject: 1986 resp = await self._request( 1987 RequestMethod.GET, 1988 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1989 json={"head": head}, 1990 ) 1991 assert isinstance(resp, dict) 1992 return resp 1993 1994 async def search_content_with_text( 1995 self, 1996 locale: str, 1997 /, 1998 content_type: str, 1999 search_text: str, 2000 tag: str, 2001 *, 2002 page: undefined.UndefinedOr[int] = undefined.Undefined, 2003 source: undefined.UndefinedOr[str] = undefined.Undefined, 2004 ) -> typedefs.JSONObject: 2005 2006 body: typedefs.JSONObject = {} 2007 2008 body["ctype"] = content_type 2009 body["searchtext"] = search_text 2010 body["tag"] = tag 2011 2012 if page is not undefined.Undefined: 2013 body["currentpage"] = page 2014 else: 2015 body["currentpage"] = 1 2016 2017 if source is not undefined.Undefined: 2018 body["source"] = source 2019 else: 2020 source = "" 2021 resp = await self._request( 2022 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp 2026 2027 async def search_content_by_tag_and_type( 2028 self, 2029 locale: str, 2030 tag: str, 2031 type: str, 2032 *, 2033 page: undefined.UndefinedOr[int] = undefined.Undefined, 2034 ) -> typedefs.JSONObject: 2035 body: typedefs.JSONObject = {} 2036 body["currentpage"] = 1 if page is undefined.Undefined else page 2037 resp = await self._request( 2038 RequestMethod.GET, 2039 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2040 json=body, 2041 ) 2042 assert isinstance(resp, dict) 2043 return resp 2044 2045 async def search_help_articles( 2046 self, text: str, size: str, / 2047 ) -> typedefs.JSONObject: 2048 resp = await self._request( 2049 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 2050 ) 2051 assert isinstance(resp, dict) 2052 return resp 2053 2054 async def fetch_topics_page( 2055 self, 2056 category_filter: int, 2057 group: int, 2058 date_filter: int, 2059 sort: typing.Union[str, bytes], 2060 *, 2061 page: undefined.UndefinedOr[int] = undefined.Undefined, 2062 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2063 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2064 ) -> typedefs.JSONObject: 2065 2066 body: typedefs.JSONObject = {} 2067 if locales is not undefined.Undefined: 2068 body["locales"] = ",".join(str(locales)) 2069 else: 2070 body["locales"] = ",".join([]) 2071 2072 if tag_filter is not undefined.Undefined: 2073 body["tagstring"] = tag_filter 2074 else: 2075 body["tagstring"] = "" 2076 2077 page = 0 if page is not undefined.Undefined else page 2078 2079 resp = await self._request( 2080 RequestMethod.GET, 2081 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2082 json=body, 2083 ) 2084 assert isinstance(resp, dict) 2085 return resp 2086 2087 async def fetch_core_topics_page( 2088 self, 2089 category_filter: int, 2090 date_filter: int, 2091 sort: typing.Union[str, bytes], 2092 *, 2093 page: undefined.UndefinedOr[int] = undefined.Undefined, 2094 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2095 ) -> typedefs.JSONObject: 2096 body: typedefs.JSONObject = {} 2097 2098 if locales is not undefined.Undefined: 2099 body["locales"] = ",".join(str(locales)) 2100 else: 2101 body["locales"] = ",".join([]) 2102 2103 resp = await self._request( 2104 RequestMethod.GET, 2105 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2106 f"/{sort!s}/{date_filter}/{category_filter}/", 2107 json=body, 2108 ) 2109 assert isinstance(resp, dict) 2110 return resp 2111 2112 async def fetch_posts_threaded_page( 2113 self, 2114 parent_post: bool, 2115 page: int, 2116 page_size: int, 2117 parent_post_id: int, 2118 reply_size: int, 2119 root_thread_mode: bool, 2120 sort_mode: int, 2121 show_banned: typing.Optional[str] = None, 2122 ) -> typedefs.JSONObject: 2123 resp = await self._request( 2124 RequestMethod.GET, 2125 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2126 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2127 json={"showbanned": show_banned}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp 2131 2132 async def fetch_posts_threaded_page_from_child( 2133 self, 2134 child_id: bool, 2135 page: int, 2136 page_size: int, 2137 reply_size: int, 2138 root_thread_mode: bool, 2139 sort_mode: int, 2140 show_banned: typing.Optional[str] = None, 2141 ) -> typedefs.JSONObject: 2142 resp = await self._request( 2143 RequestMethod.GET, 2144 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2145 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2146 json={"showbanned": show_banned}, 2147 ) 2148 assert isinstance(resp, dict) 2149 return resp 2150 2151 async def fetch_post_and_parent( 2152 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2153 ) -> typedefs.JSONObject: 2154 resp = await self._request( 2155 RequestMethod.GET, 2156 f"Forum/GetPostAndParent/{child_id}/", 2157 json={"showbanned": show_banned}, 2158 ) 2159 assert isinstance(resp, dict) 2160 return resp 2161 2162 async def fetch_posts_and_parent_awaiting( 2163 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2164 ) -> typedefs.JSONObject: 2165 resp = await self._request( 2166 RequestMethod.GET, 2167 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2168 json={"showbanned": show_banned}, 2169 ) 2170 assert isinstance(resp, dict) 2171 return resp 2172 2173 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2174 resp = await self._request( 2175 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2176 ) 2177 assert isinstance(resp, int) 2178 return resp 2179 2180 async def fetch_forum_tag_suggestions( 2181 self, partial_tag: str, / 2182 ) -> typedefs.JSONObject: 2183 resp = await self._request( 2184 RequestMethod.GET, 2185 "Forum/GetForumTagSuggestions/", 2186 json={"partialtag": partial_tag}, 2187 ) 2188 assert isinstance(resp, dict) 2189 return resp 2190 2191 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2192 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2193 assert isinstance(resp, dict) 2194 return resp 2195 2196 async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray: 2197 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2198 assert isinstance(resp, list) 2199 return resp 2200 2201 async def fetch_recommended_groups( 2202 self, 2203 accecss_token: str, 2204 /, 2205 *, 2206 date_range: int = 0, 2207 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2208 ) -> typedefs.JSONArray: 2209 resp = await self._request( 2210 RequestMethod.POST, 2211 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2212 auth=accecss_token, 2213 ) 2214 assert isinstance(resp, list) 2215 return resp 2216 2217 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2218 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2219 assert isinstance(resp, dict) 2220 return resp 2221 2222 async def fetch_user_clan_invite_setting( 2223 self, 2224 access_token: str, 2225 /, 2226 membership_type: typedefs.IntAnd[enums.MembershipType], 2227 ) -> bool: 2228 resp = await self._request( 2229 RequestMethod.GET, 2230 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2231 auth=access_token, 2232 ) 2233 assert isinstance(resp, bool) 2234 return resp 2235 2236 async def fetch_banned_group_members( 2237 self, access_token: str, group_id: int, /, *, page: int = 1 2238 ) -> typedefs.JSONObject: 2239 resp = await self._request( 2240 RequestMethod.GET, 2241 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2242 auth=access_token, 2243 ) 2244 assert isinstance(resp, dict) 2245 return resp 2246 2247 async def fetch_pending_group_memberships( 2248 self, access_token: str, group_id: int, /, *, current_page: int = 1 2249 ) -> typedefs.JSONObject: 2250 resp = await self._request( 2251 RequestMethod.GET, 2252 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2253 auth=access_token, 2254 ) 2255 assert isinstance(resp, dict) 2256 return resp 2257 2258 async def fetch_invited_group_memberships( 2259 self, access_token: str, group_id: int, /, *, current_page: int = 1 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.GET, 2263 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2264 auth=access_token, 2265 ) 2266 assert isinstance(resp, dict) 2267 return resp 2268 2269 async def invite_member_to_group( 2270 self, 2271 access_token: str, 2272 /, 2273 group_id: int, 2274 membership_id: int, 2275 membership_type: typedefs.IntAnd[enums.MembershipType], 2276 *, 2277 message: undefined.UndefinedOr[str] = undefined.Undefined, 2278 ) -> typedefs.JSONObject: 2279 resp = await self._request( 2280 RequestMethod.POST, 2281 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2282 auth=access_token, 2283 json={"message": str(message)}, 2284 ) 2285 assert isinstance(resp, dict) 2286 return resp 2287 2288 async def cancel_group_member_invite( 2289 self, 2290 access_token: str, 2291 /, 2292 group_id: int, 2293 membership_id: int, 2294 membership_type: typedefs.IntAnd[enums.MembershipType], 2295 ) -> typedefs.JSONObject: 2296 resp = await self._request( 2297 RequestMethod.POST, 2298 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2299 auth=access_token, 2300 ) 2301 assert isinstance(resp, dict) 2302 return resp 2303 2304 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2305 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2306 assert isinstance(resp, dict) 2307 return resp 2308 2309 async def fetch_historical_stats( 2310 self, 2311 character_id: int, 2312 membership_id: int, 2313 membership_type: typedefs.IntAnd[enums.MembershipType], 2314 day_start: datetime.datetime, 2315 day_end: datetime.datetime, 2316 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2317 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2318 *, 2319 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2320 ) -> typedefs.JSONObject: 2321 2322 end, start = time.parse_date_range(day_end, day_start) 2323 resp = await self._request( 2324 RequestMethod.GET, 2325 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2326 json={ 2327 "dayend": end, 2328 "daystart": start, 2329 "groups": [str(int(group)) for group in groups], 2330 "modes": [str(int(mode)) for mode in modes], 2331 "periodType": int(period_type), 2332 }, 2333 ) 2334 assert isinstance(resp, dict) 2335 return resp 2336 2337 async def fetch_historical_stats_for_account( 2338 self, 2339 membership_id: int, 2340 membership_type: typedefs.IntAnd[enums.MembershipType], 2341 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2342 ) -> typedefs.JSONObject: 2343 resp = await self._request( 2344 RequestMethod.GET, 2345 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2346 json={"groups": [str(int(group)) for group in groups]}, 2347 ) 2348 assert isinstance(resp, dict) 2349 return resp 2350 2351 async def fetch_aggregated_activity_stats( 2352 self, 2353 character_id: int, 2354 membership_id: int, 2355 membership_type: typedefs.IntAnd[enums.MembershipType], 2356 /, 2357 ) -> typedefs.JSONObject: 2358 resp = await self._request( 2359 RequestMethod.GET, 2360 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2361 f"Character/{character_id}/Stats/AggregateActivityStats/", 2362 ) 2363 assert isinstance(resp, dict) 2364 return resp
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is also used within aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
async def main():
async with aiobungie.RESTClient("TOKEN") as rest_client:
req = await rest_client.fetch_clan_members(4389205)
clan_members = req['results']
for member in clan_members:
for k, v in member['destinyUserInfo'].items():
print(k, v)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
425 def __init__( 426 self, 427 token: str, 428 /, 429 client_secret: typing.Optional[str] = None, 430 client_id: typing.Optional[int] = None, 431 *, 432 max_retries: int = 4, 433 max_ratelimit_retries: int = 3, 434 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 435 ) -> None: 436 self._session: typing.Optional[_Session] = None 437 self._lock: typing.Optional[asyncio.Lock] = None 438 self._client_secret = client_secret 439 self._client_id = client_id 440 self._token: str = token 441 self._max_retries = max_retries 442 self._max_rate_limit_retries = max_ratelimit_retries 443 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 444 445 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
459 @typing.final 460 async def close(self) -> None: 461 session = self._get_session() 462 await session.close() 463 self._session = None
Close this REST client session if it was acquired.
This method is automatically called when using async with contextmanager.
Raises
RuntimeError: If the client is already closed.
465 @typing.final 466 def open(self) -> None: 467 """Open a new client session. This is called internally with contextmanager usage.""" 468 if self.is_alive: 469 raise RuntimeError("Cannot open a new session while it's already open.") 470 471 self._session = _Session.create( 472 owner=False, 473 raise_status=False, 474 connect=None, 475 socket_read=None, 476 socket_connect=None, 477 )
Open a new client session. This is called internally with contextmanager usage.
479 @typing.final 480 def enable_debugging( 481 self, 482 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 483 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 484 /, 485 ) -> None: 486 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
488 @typing.final 489 async def static_request( 490 self, 491 method: typing.Union[RequestMethod, str], 492 path: str, 493 *, 494 auth: typing.Optional[str] = None, 495 json: typing.Optional[dict[str, typing.Any]] = None, 496 ) -> ResponseSig: 497 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
aiobungie.RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
499 @typing.final 500 def build_oauth2_url( 501 self, client_id: typing.Optional[int] = None 502 ) -> typing.Optional[str]: 503 client_id = client_id or self._client_id 504 if client_id is None: 505 return None 506 507 return url.OAUTH2_EP_BUILDER.format( 508 oauth_endpoint=url.OAUTH_EP, 509 client_id=client_id, 510 uuid=_uuid(), 511 )
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
str | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete URL will be returned. OtherwiseNonewill be returned.
738 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 739 740 if not isinstance(self._client_id, int): 741 raise TypeError( 742 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 743 ) 744 745 if not isinstance(self._client_secret, str): 746 raise TypeError( 747 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 748 ) 749 750 headers = { 751 "client_secret": self._client_secret, 752 } 753 754 data = ( 755 f"grant_type=authorization_code&code={code}" 756 f"&client_id={self._client_id}&client_secret={self._client_secret}" 757 ) 758 759 response = await self._request( 760 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 761 ) 762 assert isinstance(response, dict) 763 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
aiobungie.Unauthorized: The passed code was invalid.
765 async def refresh_access_token( 766 self, refresh_token: str, / 767 ) -> builders.OAuth2Response: 768 if not isinstance(self._client_id, int): 769 raise TypeError( 770 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 771 ) 772 773 if not isinstance(self._client_secret, str): 774 raise TypeError( 775 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 776 ) 777 778 data = { 779 "grant_type": "refresh_token", 780 "refresh_token": refresh_token, 781 "client_id": self._client_id, 782 "client_secret": self._client_secret, 783 "Content-Type": "application/x-www-form-urlencoded", 784 } 785 786 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 787 assert isinstance(response, dict) 788 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
790 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 791 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 792 resp = await self._request( 793 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 794 ) 795 assert isinstance(resp, dict) 796 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
aiobungie.NotFound: The user was not found.
804 async def fetch_membership_from_id( 805 self, 806 id: int, 807 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 808 /, 809 ) -> typedefs.JSONObject: 810 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 811 resp = await self._request( 812 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 813 ) 814 assert isinstance(resp, dict) 815 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
817 async def fetch_player( 818 self, 819 name: str, 820 code: int, 821 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 822 /, 823 ) -> typedefs.JSONArray: 824 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 825 resp = await self._request( 826 RequestMethod.POST, 827 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 828 json={"displayName": name, "displayNameCode": code}, 829 ) 830 assert isinstance(resp, list) 831 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
833 async def search_users(self, name: str, /) -> typedefs.JSONObject: 834 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 835 resp = await self._request( 836 RequestMethod.POST, 837 "User/Search/GlobalName/0", 838 json={"displayNamePrefix": name}, 839 ) 840 assert isinstance(resp, dict) 841 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
843 async def fetch_clan_from_id( 844 self, id: int, /, access_token: typing.Optional[str] = None 845 ) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 849 ) 850 assert isinstance(resp, dict) 851 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
853 async def fetch_clan( 854 self, 855 name: str, 856 /, 857 access_token: typing.Optional[str] = None, 858 *, 859 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 860 ) -> typedefs.JSONObject: 861 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 862 resp = await self._request( 863 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 864 ) 865 assert isinstance(resp, dict) 866 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
868 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 869 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 870 resp = await self._request( 871 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 872 ) 873 assert isinstance(resp, dict) 874 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
876 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 877 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 878 resp = await self._request( 879 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 880 ) 881 assert isinstance(resp, list) 882 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
884 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 885 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 886 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 887 assert isinstance(resp, dict) 888 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
890 async def fetch_character( 891 self, 892 member_id: int, 893 membership_type: typedefs.IntAnd[enums.MembershipType], 894 character_id: int, 895 components: list[enums.ComponentType], 896 auth: typing.Optional[str] = None, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 collector = _collect_components(components) 900 response = await self._request( 901 RequestMethod.GET, 902 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 903 f"Character/{character_id}/?components={collector}", 904 auth=auth, 905 ) 906 assert isinstance(response, dict) 907 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
909 async def fetch_activities( 910 self, 911 member_id: int, 912 character_id: int, 913 mode: typedefs.IntAnd[enums.GameMode], 914 membership_type: typedefs.IntAnd[ 915 enums.MembershipType 916 ] = enums.MembershipType.ALL, 917 *, 918 page: int = 0, 919 limit: int = 1, 920 ) -> typedefs.JSONObject: 921 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 922 resp = await self._request( 923 RequestMethod.GET, 924 f"Destiny2/{int(membership_type)}/Account/" 925 f"{member_id}/Character/{character_id}/Stats/Activities" 926 f"/?mode={int(mode)}&count={limit}&page={page}", 927 ) 928 assert isinstance(resp, dict) 929 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
aiobungie.NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
931 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 932 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 933 resp = await self._request( 934 RequestMethod.GET, 935 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 936 ) 937 assert isinstance(resp, dict) 938 return resp
940 async def fetch_profile( 941 self, 942 membership_id: int, 943 type: typedefs.IntAnd[enums.MembershipType], 944 components: list[enums.ComponentType], 945 auth: typing.Optional[str] = None, 946 ) -> typedefs.JSONObject: 947 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 948 collector = _collect_components(components) 949 response = await self._request( 950 RequestMethod.GET, 951 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 952 auth=auth, 953 ) 954 assert isinstance(response, dict) 955 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
957 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 958 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 959 response = await self._request( 960 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 961 ) 962 assert isinstance(response, dict) 963 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
965 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 966 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 967 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 968 assert isinstance(resp, dict) 969 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
971 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 972 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 973 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 974 assert isinstance(resp, dict) 975 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objetive data.
977 async def fetch_groups_for_member( 978 self, 979 member_id: int, 980 member_type: typedefs.IntAnd[enums.MembershipType], 981 /, 982 *, 983 filter: int = 0, 984 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 985 ) -> typedefs.JSONObject: 986 resp = await self._request( 987 RequestMethod.GET, 988 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 989 ) 990 assert isinstance(resp, dict) 991 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
993 async def fetch_potential_groups_for_member( 994 self, 995 member_id: int, 996 member_type: typedefs.IntAnd[enums.MembershipType], 997 /, 998 *, 999 filter: int = 0, 1000 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 1001 ) -> typedefs.JSONObject: 1002 resp = await self._request( 1003 RequestMethod.GET, 1004 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 1005 ) 1006 assert isinstance(resp, dict) 1007 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
1009 async def fetch_clan_members( 1010 self, 1011 clan_id: int, 1012 /, 1013 *, 1014 name: typing.Optional[str] = None, 1015 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 1016 ) -> typedefs.JSONObject: 1017 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1018 resp = await self._request( 1019 RequestMethod.GET, 1020 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1021 ) 1022 assert isinstance(resp, dict) 1023 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
builsins.int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
1025 async def fetch_hardlinked_credentials( 1026 self, 1027 credential: int, 1028 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1029 /, 1030 ) -> typedefs.JSONObject: 1031 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1032 resp = await self._request( 1033 RequestMethod.GET, 1034 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1035 ) 1036 assert isinstance(resp, dict) 1037 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The crededntial type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
1039 async def fetch_user_credentials( 1040 self, access_token: str, membership_id: int, / 1041 ) -> typedefs.JSONArray: 1042 resp = await self._request( 1043 RequestMethod.GET, 1044 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1045 auth=access_token, 1046 ) 1047 assert isinstance(resp, list) 1048 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1050 async def insert_socket_plug( 1051 self, 1052 action_token: str, 1053 /, 1054 instance_id: int, 1055 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1056 character_id: int, 1057 membership_type: typedefs.IntAnd[enums.MembershipType], 1058 ) -> typedefs.JSONObject: 1059 1060 if isinstance(plug, builders.PlugSocketBuilder): 1061 plug = plug.collect() 1062 1063 body = { 1064 "actionToken": action_token, 1065 "itemInstanceId": instance_id, 1066 "plug": plug, 1067 "characterId": character_id, 1068 "membershipType": int(membership_type), 1069 } 1070 resp = await self._request( 1071 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1072 ) 1073 assert isinstance(resp, dict) 1074 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1076 async def insert_socket_plug_free( 1077 self, 1078 access_token: str, 1079 /, 1080 instance_id: int, 1081 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1082 character_id: int, 1083 membership_type: typedefs.IntAnd[enums.MembershipType], 1084 ) -> typedefs.JSONObject: 1085 1086 if isinstance(plug, builders.PlugSocketBuilder): 1087 plug = plug.collect() 1088 1089 body = { 1090 "itemInstanceId": instance_id, 1091 "plug": plug, 1092 "characterId": character_id, 1093 "membershipType": int(membership_type), 1094 } 1095 resp = await self._request( 1096 RequestMethod.POST, 1097 "Destiny2/Actions/Items/InsertSocketPlugFree", 1098 json=body, 1099 auth=access_token, 1100 ) 1101 assert isinstance(resp, dict) 1102 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1104 async def set_item_lock_state( 1105 self, 1106 access_token: str, 1107 state: bool, 1108 /, 1109 item_id: int, 1110 character_id: int, 1111 membership_type: typedefs.IntAnd[enums.MembershipType], 1112 ) -> int: 1113 body = { 1114 "state": state, 1115 "itemId": item_id, 1116 "characterId": character_id, 1117 "membership_type": int(membership_type), 1118 } 1119 response = await self._request( 1120 RequestMethod.POST, 1121 "Destiny2/Actions/Items/SetLockState", 1122 json=body, 1123 auth=access_token, 1124 ) 1125 assert isinstance(response, int) 1126 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1128 async def set_quest_track_state( 1129 self, 1130 access_token: str, 1131 state: bool, 1132 /, 1133 item_id: int, 1134 character_id: int, 1135 membership_type: typedefs.IntAnd[enums.MembershipType], 1136 ) -> int: 1137 body = { 1138 "state": state, 1139 "itemId": item_id, 1140 "characterId": character_id, 1141 "membership_type": int(membership_type), 1142 } 1143 response = await self._request( 1144 RequestMethod.POST, 1145 "Destiny2/Actions/Items/SetTrackedState", 1146 json=body, 1147 auth=access_token, 1148 ) 1149 assert isinstance(response, int) 1150 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1152 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1153 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1154 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1155 assert isinstance(path, dict) 1156 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1158 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1159 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1160 _ensure_manifest_language(language) 1161 1162 content = await self.fetch_manifest_path() 1163 resp = await self._request( 1164 RequestMethod.GET, 1165 content["mobileWorldContentPaths"][language], 1166 unwrapping="read", 1167 base=True, 1168 ) 1169 assert isinstance(resp, bytes) 1170 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1172 async def download_manifest( 1173 self, 1174 language: str = "en", 1175 name: str = "manifest", 1176 path: typing.Union[pathlib.Path, str] = ".", 1177 *, 1178 force: bool = False, 1179 ) -> None: 1180 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1181 complete_path = _get_path(name, path, sql=True) 1182 1183 if complete_path.exists() and force: 1184 if force: 1185 _LOG.info( 1186 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1187 ) 1188 complete_path.unlink(missing_ok=True) 1189 1190 return await self.download_manifest(language, name, path, force=force) 1191 1192 else: 1193 raise FileExistsError( 1194 "Manifest file already exists, " 1195 "To force download, set the `force` parameter to `True`." 1196 ) 1197 1198 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1199 data_bytes = await self.read_manifest_bytes(language) 1200 await asyncio.get_running_loop().run_in_executor( 1201 None, _write_sqlite_bytes, data_bytes, path, name 1202 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - path (
str|pathlib.Path): The path to save the manifest sqlite database. Example"D:/", Default is the current directory. - name (
str): The manifest database file name. Default ismanifest - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
Raises
FileNotFoundError: If the manifest file exists andforceisFalse.ValueError: If the provided language was not recognized.
1204 async def download_json_manifest( 1205 self, 1206 file_name: str = "manifest", 1207 path: typing.Union[str, pathlib.Path] = ".", 1208 language: str = "en", 1209 ) -> None: 1210 _ensure_manifest_language(language) 1211 1212 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1213 1214 content = await self.fetch_manifest_path() 1215 json_bytes = await self._request( 1216 RequestMethod.GET, 1217 content["jsonWorldContentPaths"][language], 1218 unwrapping="read", 1219 base=True, 1220 ) 1221 1222 await asyncio.get_running_loop().run_in_executor( 1223 None, _write_json_bytes, json_bytes, file_name, path 1224 ) 1225 _LOG.info("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- file_name (
str): The file name to save the manifest json file. Default ismanifest. - path (
str|pathlib.Path): The path to save the manifest json file. Default is the current directory. Example"D:/" - language (
str): The manifest database language bytes to get. Default is English.
1227 async def fetch_manifest_version(self) -> str: 1228 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1230 async def fetch_linked_profiles( 1231 self, 1232 member_id: int, 1233 member_type: typedefs.IntAnd[enums.MembershipType], 1234 /, 1235 *, 1236 all: bool = False, 1237 ) -> typedefs.JSONObject: 1238 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1239 resp = await self._request( 1240 RequestMethod.GET, 1241 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1242 ) 1243 assert isinstance(resp, dict) 1244 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether thry're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1254 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1257 assert isinstance(resp, dict) 1258 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1260 async def fetch_public_milestone_content( 1261 self, milestone_hash: int, / 1262 ) -> typedefs.JSONObject: 1263 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1264 resp = await self._request( 1265 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1266 ) 1267 assert isinstance(resp, dict) 1268 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1270 async def fetch_current_user_memberships( 1271 self, access_token: str, / 1272 ) -> typedefs.JSONObject: 1273 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1274 resp = await self._request( 1275 RequestMethod.GET, 1276 "User/GetMembershipsForCurrentUser/", 1277 auth=access_token, 1278 ) 1279 assert isinstance(resp, dict) 1280 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1282 async def equip_item( 1283 self, 1284 access_token: str, 1285 /, 1286 item_id: int, 1287 character_id: int, 1288 membership_type: typedefs.IntAnd[enums.MembershipType], 1289 ) -> None: 1290 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1291 payload = { 1292 "itemId": item_id, 1293 "characterId": character_id, 1294 "membershipType": int(membership_type), 1295 } 1296 1297 await self._request( 1298 RequestMethod.POST, 1299 "Destiny2/Actions/Items/EquipItem/", 1300 json=payload, 1301 auth=access_token, 1302 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1304 async def equip_items( 1305 self, 1306 access_token: str, 1307 /, 1308 item_ids: list[int], 1309 character_id: int, 1310 membership_type: typedefs.IntAnd[enums.MembershipType], 1311 ) -> None: 1312 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1313 payload = { 1314 "itemIds": item_ids, 1315 "characterId": character_id, 1316 "membershipType": int(membership_type), 1317 } 1318 await self._request( 1319 RequestMethod.POST, 1320 "Destiny2/Actions/Items/EquipItems/", 1321 json=payload, 1322 auth=access_token, 1323 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1325 async def ban_clan_member( 1326 self, 1327 access_token: str, 1328 /, 1329 group_id: int, 1330 membership_id: int, 1331 membership_type: typedefs.IntAnd[enums.MembershipType], 1332 *, 1333 length: int = 0, 1334 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1335 ) -> None: 1336 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1337 payload = {"comment": str(comment), "length": length} 1338 await self._request( 1339 RequestMethod.POST, 1340 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1341 json=payload, 1342 auth=access_token, 1343 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1345 async def unban_clan_member( 1346 self, 1347 access_token: str, 1348 /, 1349 group_id: int, 1350 membership_id: int, 1351 membership_type: typedefs.IntAnd[enums.MembershipType], 1352 ) -> None: 1353 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1354 await self._request( 1355 RequestMethod.POST, 1356 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1357 auth=access_token, 1358 )
Unbans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1360 async def kick_clan_member( 1361 self, 1362 access_token: str, 1363 /, 1364 group_id: int, 1365 membership_id: int, 1366 membership_type: typedefs.IntAnd[enums.MembershipType], 1367 ) -> typedefs.JSONObject: 1368 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1369 resp = await self._request( 1370 RequestMethod.POST, 1371 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1372 auth=access_token, 1373 ) 1374 assert isinstance(resp, dict) 1375 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1377 async def edit_clan( 1378 self, 1379 access_token: str, 1380 /, 1381 group_id: int, 1382 *, 1383 name: typedefs.NoneOr[str] = None, 1384 about: typedefs.NoneOr[str] = None, 1385 motto: typedefs.NoneOr[str] = None, 1386 theme: typedefs.NoneOr[str] = None, 1387 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1388 is_public: typedefs.NoneOr[bool] = None, 1389 locale: typedefs.NoneOr[str] = None, 1390 avatar_image_index: typedefs.NoneOr[int] = None, 1391 membership_option: typedefs.NoneOr[ 1392 typedefs.IntAnd[enums.MembershipOption] 1393 ] = None, 1394 allow_chat: typedefs.NoneOr[bool] = None, 1395 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1396 call_sign: typedefs.NoneOr[str] = None, 1397 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1398 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1399 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1400 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1401 ) -> None: 1402 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1403 payload = { 1404 "name": name, 1405 "about": about, 1406 "motto": motto, 1407 "theme": theme, 1408 "tags": tags, 1409 "isPublic": is_public, 1410 "avatarImageIndex": avatar_image_index, 1411 "isPublicTopicAdminOnly": is_public_topic_admin, 1412 "allowChat": allow_chat, 1413 "chatSecurity": chat_security, 1414 "callsign": call_sign, 1415 "homepage": homepage, 1416 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1417 "defaultPublicity": default_publicity, 1418 "locale": locale, 1419 } 1420 if membership_option is not None: 1421 payload["membershipOption"] = int(membership_option) 1422 1423 await self._request( 1424 RequestMethod.POST, 1425 f"GroupV2/{group_id}/Edit", 1426 json=payload, 1427 auth=access_token, 1428 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1430 async def edit_clan_options( 1431 self, 1432 access_token: str, 1433 /, 1434 group_id: int, 1435 *, 1436 invite_permissions_override: typedefs.NoneOr[bool] = None, 1437 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1438 host_guided_game_permission_override: typedefs.NoneOr[ 1439 typing.Literal[0, 1, 2] 1440 ] = None, 1441 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1442 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1443 ) -> None: 1444 1445 payload = { 1446 "InvitePermissionOverride": invite_permissions_override, 1447 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1448 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1449 "UpdateBannerPermissionOverride": update_banner_permission_override, 1450 "JoinLevel": int(join_level) if join_level else None, 1451 } 1452 1453 await self._request( 1454 RequestMethod.POST, 1455 f"GroupV2/{group_id}/EditFounderOptions", 1456 json=payload, 1457 auth=access_token, 1458 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1460 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1461 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1462 resp = await self._request( 1463 RequestMethod.GET, 1464 "Social/Friends/", 1465 auth=access_token, 1466 ) 1467 assert isinstance(resp, dict) 1468 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1470 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 resp = await self._request( 1473 RequestMethod.GET, 1474 "Social/Friends/Requests", 1475 auth=access_token, 1476 ) 1477 assert isinstance(resp, dict) 1478 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1480 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Accept/{member_id}", 1485 auth=access_token, 1486 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1488 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Add/{member_id}", 1493 auth=access_token, 1494 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1496 async def decline_friend_request( 1497 self, access_token: str, /, member_id: int 1498 ) -> None: 1499 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1500 await self._request( 1501 RequestMethod.POST, 1502 f"Social/Friends/Requests/Decline/{member_id}", 1503 auth=access_token, 1504 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1506 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1507 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1508 await self._request( 1509 RequestMethod.POST, 1510 f"Social/Friends/Remove/{member_id}", 1511 auth=access_token, 1512 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1514 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1515 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1516 await self._request( 1517 RequestMethod.POST, 1518 f"Social/Friends/Requests/Remove/{member_id}", 1519 auth=access_token, 1520 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1522 async def approve_all_pending_group_users( 1523 self, 1524 access_token: str, 1525 /, 1526 group_id: int, 1527 message: undefined.UndefinedOr[str] = undefined.Undefined, 1528 ) -> None: 1529 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1530 await self._request( 1531 RequestMethod.POST, 1532 f"GroupV2/{group_id}/Members/ApproveAll", 1533 auth=access_token, 1534 json={"message": str(message)}, 1535 )
Apporve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1537 async def deny_all_pending_group_users( 1538 self, 1539 access_token: str, 1540 /, 1541 group_id: int, 1542 *, 1543 message: undefined.UndefinedOr[str] = undefined.Undefined, 1544 ) -> None: 1545 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/Members/DenyAll", 1549 auth=access_token, 1550 json={"message": str(message)}, 1551 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1553 async def add_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 *, 1559 name: undefined.UndefinedOr[str] = undefined.Undefined, 1560 security: typing.Literal[0, 1] = 0, 1561 ) -> None: 1562 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1563 payload = {"chatName": str(name), "chatSecurity": security} 1564 await self._request( 1565 RequestMethod.POST, 1566 f"GroupV2/{group_id}/OptionalConversations/Add", 1567 json=payload, 1568 auth=access_token, 1569 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1571 async def edit_optional_conversation( 1572 self, 1573 access_token: str, 1574 /, 1575 group_id: int, 1576 conversation_id: int, 1577 *, 1578 name: undefined.UndefinedOr[str] = undefined.Undefined, 1579 security: typing.Literal[0, 1] = 0, 1580 enable_chat: bool = False, 1581 ) -> None: 1582 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1583 payload = { 1584 "chatEnabled": enable_chat, 1585 "chatName": str(name), 1586 "chatSecurity": security, 1587 } 1588 await self._request( 1589 RequestMethod.POST, 1590 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1591 json=payload, 1592 auth=access_token, 1593 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1595 async def transfer_item( 1596 self, 1597 access_token: str, 1598 /, 1599 item_id: int, 1600 item_hash: int, 1601 character_id: int, 1602 member_type: typedefs.IntAnd[enums.MembershipType], 1603 *, 1604 stack_size: int = 1, 1605 vault: bool = False, 1606 ) -> None: 1607 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1608 payload = { 1609 "characterId": character_id, 1610 "membershipType": int(member_type), 1611 "itemId": item_id, 1612 "itemReferenceHash": item_hash, 1613 "stackSize": stack_size, 1614 "transferToVault": vault, 1615 } 1616 await self._request( 1617 RequestMethod.POST, 1618 "Destiny2/Actions/Items/TransferItem", 1619 json=payload, 1620 auth=access_token, 1621 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to trasnfer this item to your valut or not. Defaults toFalse.
1623 async def pull_item( 1624 self, 1625 access_token: str, 1626 /, 1627 item_id: int, 1628 item_hash: int, 1629 character_id: int, 1630 member_type: typedefs.IntAnd[enums.MembershipType], 1631 *, 1632 stack_size: int = 1, 1633 vault: bool = False, 1634 ) -> None: 1635 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1636 payload = { 1637 "characterId": character_id, 1638 "membershipType": int(member_type), 1639 "itemId": item_id, 1640 "itemReferenceHash": item_hash, 1641 "stackSize": stack_size, 1642 "transferToVault": vault, 1643 } 1644 await self._request( 1645 RequestMethod.POST, 1646 "Destiny2/Actions/Items/PullFromPostmaster", 1647 json=payload, 1648 auth=access_token, 1649 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to pill this item to your valut or not. Defaults toFalse.
1651 async def fetch_fireteams( 1652 self, 1653 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1654 *, 1655 platform: typedefs.IntAnd[ 1656 fireteams.FireteamPlatform 1657 ] = fireteams.FireteamPlatform.ANY, 1658 language: typing.Union[ 1659 fireteams.FireteamLanguage, str 1660 ] = fireteams.FireteamLanguage.ALL, 1661 date_range: typedefs.IntAnd[ 1662 fireteams.FireteamDate 1663 ] = fireteams.FireteamDate.ALL, 1664 page: int = 0, 1665 slots_filter: int = 0, 1666 ) -> typedefs.JSONObject: 1667 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1668 resp = await self._request( 1669 RequestMethod.GET, 1670 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1671 ) 1672 assert isinstance(resp, dict) 1673 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1675 async def fetch_avaliable_clan_fireteams( 1676 self, 1677 access_token: str, 1678 group_id: int, 1679 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1680 *, 1681 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1682 language: typing.Union[fireteams.FireteamLanguage, str], 1683 date_range: typedefs.IntAnd[ 1684 fireteams.FireteamDate 1685 ] = fireteams.FireteamDate.ALL, 1686 page: int = 0, 1687 public_only: bool = False, 1688 slots_filter: int = 0, 1689 ) -> typedefs.JSONObject: 1690 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1691 resp = await self._request( 1692 RequestMethod.GET, 1693 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1694 json={"langFilter": str(language)}, 1695 auth=access_token, 1696 ) 1697 assert isinstance(resp, dict) 1698 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1700 async def fetch_clan_fireteam( 1701 self, access_token: str, fireteam_id: int, group_id: int 1702 ) -> typedefs.JSONObject: 1703 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1704 resp = await self._request( 1705 RequestMethod.GET, 1706 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1707 auth=access_token, 1708 ) 1709 assert isinstance(resp, dict) 1710 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1712 async def fetch_my_clan_fireteams( 1713 self, 1714 access_token: str, 1715 group_id: int, 1716 *, 1717 include_closed: bool = True, 1718 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1719 language: typing.Union[fireteams.FireteamLanguage, str], 1720 filtered: bool = True, 1721 page: int = 0, 1722 ) -> typedefs.JSONObject: 1723 payload = {"groupFilter": filtered, "langFilter": str(language)} 1724 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1725 resp = await self._request( 1726 RequestMethod.GET, 1727 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1728 json=payload, 1729 auth=access_token, 1730 ) 1731 assert isinstance(resp, dict) 1732 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1734 async def fetch_private_clan_fireteams( 1735 self, access_token: str, group_id: int, / 1736 ) -> int: 1737 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1738 resp = await self._request( 1739 RequestMethod.GET, 1740 f"Fireteam/Clan/{group_id}/ActiveCount", 1741 auth=access_token, 1742 ) 1743 assert isinstance(resp, int) 1744 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1746 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1747 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1748 resp = await self._request( 1749 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1750 ) 1751 assert isinstance(resp, dict) 1752 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1754 async def search_entities( 1755 self, name: str, entity_type: str, *, page: int = 0 1756 ) -> typedefs.JSONObject: 1757 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1758 resp = await self._request( 1759 RequestMethod.GET, 1760 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1761 json={"page": page}, 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1766 async def fetch_unique_weapon_history( 1767 self, 1768 membership_id: int, 1769 character_id: int, 1770 membership_type: typedefs.IntAnd[enums.MembershipType], 1771 ) -> typedefs.JSONObject: 1772 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1773 resp = await self._request( 1774 RequestMethod.GET, 1775 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1776 ) 1777 assert isinstance(resp, dict) 1778 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1780 async def fetch_item( 1781 self, 1782 member_id: int, 1783 item_id: int, 1784 membership_type: typedefs.IntAnd[enums.MembershipType], 1785 components: list[enums.ComponentType], 1786 ) -> typedefs.JSONObject: 1787 collector = _collect_components(components) 1788 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1789 resp = await self._request( 1790 RequestMethod.GET, 1791 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1792 ) 1793 assert isinstance(resp, dict) 1794 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1796 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1797 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1798 resp = await self._request( 1799 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1800 ) 1801 assert isinstance(resp, dict) 1802 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1804 async def fetch_available_locales(self) -> typedefs.JSONObject: 1805 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1806 resp = await self._request( 1807 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1808 ) 1809 assert isinstance(resp, dict) 1810 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1812 async def fetch_common_settings(self) -> typedefs.JSONObject: 1813 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1814 resp = await self._request(RequestMethod.GET, "Settings") 1815 assert isinstance(resp, dict) 1816 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1818 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1819 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1820 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1821 assert isinstance(resp, dict) 1822 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1824 async def fetch_global_alerts( 1825 self, *, include_streaming: bool = False 1826 ) -> typedefs.JSONArray: 1827 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1828 resp = await self._request( 1829 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1830 ) 1831 assert isinstance(resp, list) 1832 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1834 async def awainitialize_request( 1835 self, 1836 access_token: str, 1837 type: typing.Literal[0, 1], 1838 membership_type: typedefs.IntAnd[enums.MembershipType], 1839 /, 1840 *, 1841 affected_item_id: typing.Optional[int] = None, 1842 character_id: typing.Optional[int] = None, 1843 ) -> typedefs.JSONObject: 1844 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1845 1846 body = {"type": type, "membershipType": int(membership_type)} 1847 1848 if affected_item_id is not None: 1849 body["affectedItemId"] = affected_item_id 1850 1851 if character_id is not None: 1852 body["characterId"] = character_id 1853 1854 resp = await self._request( 1855 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1856 ) 1857 assert isinstance(resp, dict) 1858 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1860 async def awaget_action_token( 1861 self, access_token: str, correlation_id: str, / 1862 ) -> typedefs.JSONObject: 1863 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1864 resp = await self._request( 1865 RequestMethod.POST, 1866 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1867 auth=access_token, 1868 ) 1869 assert isinstance(resp, dict) 1870 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1892 async def fetch_vendors( 1893 self, 1894 access_token: str, 1895 character_id: int, 1896 membership_id: int, 1897 membership_type: typedefs.IntAnd[enums.MembershipType], 1898 /, 1899 components: list[enums.ComponentType], 1900 filter: typing.Optional[int] = None, 1901 ) -> typedefs.JSONObject: 1902 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1903 components_ = _collect_components(components) 1904 route = ( 1905 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1906 f"/Character/{character_id}/Vendors/?components={components_}" 1907 ) 1908 1909 if filter is not None: 1910 route = route + f"&filter={filter}" 1911 1912 resp = await self._request( 1913 RequestMethod.GET, 1914 route, 1915 auth=access_token, 1916 ) 1917 assert isinstance(resp, dict) 1918 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1920 async def fetch_vendor( 1921 self, 1922 access_token: str, 1923 character_id: int, 1924 membership_id: int, 1925 membership_type: typedefs.IntAnd[enums.MembershipType], 1926 vendor_hash: int, 1927 /, 1928 components: list[enums.ComponentType], 1929 ) -> typedefs.JSONObject: 1930 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1931 components_ = _collect_components(components) 1932 resp = await self._request( 1933 RequestMethod.GET, 1934 ( 1935 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1936 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1937 ), 1938 auth=access_token, 1939 ) 1940 assert isinstance(resp, dict) 1941 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1943 async def fetch_application_api_usage( 1944 self, 1945 access_token: str, 1946 application_id: int, 1947 /, 1948 *, 1949 start: typing.Optional[datetime.datetime] = None, 1950 end: typing.Optional[datetime.datetime] = None, 1951 ) -> typedefs.JSONObject: 1952 1953 end_date, start_date = time.parse_date_range(end, start) 1954 resp = await self._request( 1955 RequestMethod.GET, 1956 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1957 auth=access_token, 1958 ) 1959 assert isinstance(resp, dict) 1960 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1962 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1963 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1964 assert isinstance(resp, list) 1965 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1972 async def fetch_content_by_id( 1973 self, id: int, locale: str, /, *, head: bool = False 1974 ) -> typedefs.JSONObject: 1975 resp = await self._request( 1976 RequestMethod.GET, 1977 f"Content/GetContentById/{id}/{locale}/", 1978 json={"head": head}, 1979 ) 1980 assert isinstance(resp, dict) 1981 return resp
1983 async def fetch_content_by_tag_and_type( 1984 self, locale: str, tag: str, type: str, *, head: bool = False 1985 ) -> typedefs.JSONObject: 1986 resp = await self._request( 1987 RequestMethod.GET, 1988 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1989 json={"head": head}, 1990 ) 1991 assert isinstance(resp, dict) 1992 return resp
1994 async def search_content_with_text( 1995 self, 1996 locale: str, 1997 /, 1998 content_type: str, 1999 search_text: str, 2000 tag: str, 2001 *, 2002 page: undefined.UndefinedOr[int] = undefined.Undefined, 2003 source: undefined.UndefinedOr[str] = undefined.Undefined, 2004 ) -> typedefs.JSONObject: 2005 2006 body: typedefs.JSONObject = {} 2007 2008 body["ctype"] = content_type 2009 body["searchtext"] = search_text 2010 body["tag"] = tag 2011 2012 if page is not undefined.Undefined: 2013 body["currentpage"] = page 2014 else: 2015 body["currentpage"] = 1 2016 2017 if source is not undefined.Undefined: 2018 body["source"] = source 2019 else: 2020 source = "" 2021 resp = await self._request( 2022 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp
2027 async def search_content_by_tag_and_type( 2028 self, 2029 locale: str, 2030 tag: str, 2031 type: str, 2032 *, 2033 page: undefined.UndefinedOr[int] = undefined.Undefined, 2034 ) -> typedefs.JSONObject: 2035 body: typedefs.JSONObject = {} 2036 body["currentpage"] = 1 if page is undefined.Undefined else page 2037 resp = await self._request( 2038 RequestMethod.GET, 2039 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2040 json=body, 2041 ) 2042 assert isinstance(resp, dict) 2043 return resp
2054 async def fetch_topics_page( 2055 self, 2056 category_filter: int, 2057 group: int, 2058 date_filter: int, 2059 sort: typing.Union[str, bytes], 2060 *, 2061 page: undefined.UndefinedOr[int] = undefined.Undefined, 2062 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2063 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2064 ) -> typedefs.JSONObject: 2065 2066 body: typedefs.JSONObject = {} 2067 if locales is not undefined.Undefined: 2068 body["locales"] = ",".join(str(locales)) 2069 else: 2070 body["locales"] = ",".join([]) 2071 2072 if tag_filter is not undefined.Undefined: 2073 body["tagstring"] = tag_filter 2074 else: 2075 body["tagstring"] = "" 2076 2077 page = 0 if page is not undefined.Undefined else page 2078 2079 resp = await self._request( 2080 RequestMethod.GET, 2081 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2082 json=body, 2083 ) 2084 assert isinstance(resp, dict) 2085 return resp
2087 async def fetch_core_topics_page( 2088 self, 2089 category_filter: int, 2090 date_filter: int, 2091 sort: typing.Union[str, bytes], 2092 *, 2093 page: undefined.UndefinedOr[int] = undefined.Undefined, 2094 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2095 ) -> typedefs.JSONObject: 2096 body: typedefs.JSONObject = {} 2097 2098 if locales is not undefined.Undefined: 2099 body["locales"] = ",".join(str(locales)) 2100 else: 2101 body["locales"] = ",".join([]) 2102 2103 resp = await self._request( 2104 RequestMethod.GET, 2105 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2106 f"/{sort!s}/{date_filter}/{category_filter}/", 2107 json=body, 2108 ) 2109 assert isinstance(resp, dict) 2110 return resp
2112 async def fetch_posts_threaded_page( 2113 self, 2114 parent_post: bool, 2115 page: int, 2116 page_size: int, 2117 parent_post_id: int, 2118 reply_size: int, 2119 root_thread_mode: bool, 2120 sort_mode: int, 2121 show_banned: typing.Optional[str] = None, 2122 ) -> typedefs.JSONObject: 2123 resp = await self._request( 2124 RequestMethod.GET, 2125 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2126 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2127 json={"showbanned": show_banned}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp
2132 async def fetch_posts_threaded_page_from_child( 2133 self, 2134 child_id: bool, 2135 page: int, 2136 page_size: int, 2137 reply_size: int, 2138 root_thread_mode: bool, 2139 sort_mode: int, 2140 show_banned: typing.Optional[str] = None, 2141 ) -> typedefs.JSONObject: 2142 resp = await self._request( 2143 RequestMethod.GET, 2144 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2145 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2146 json={"showbanned": show_banned}, 2147 ) 2148 assert isinstance(resp, dict) 2149 return resp
2151 async def fetch_post_and_parent( 2152 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2153 ) -> typedefs.JSONObject: 2154 resp = await self._request( 2155 RequestMethod.GET, 2156 f"Forum/GetPostAndParent/{child_id}/", 2157 json={"showbanned": show_banned}, 2158 ) 2159 assert isinstance(resp, dict) 2160 return resp
2162 async def fetch_posts_and_parent_awaiting( 2163 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2164 ) -> typedefs.JSONObject: 2165 resp = await self._request( 2166 RequestMethod.GET, 2167 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2168 json={"showbanned": show_banned}, 2169 ) 2170 assert isinstance(resp, dict) 2171 return resp
2201 async def fetch_recommended_groups( 2202 self, 2203 accecss_token: str, 2204 /, 2205 *, 2206 date_range: int = 0, 2207 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2208 ) -> typedefs.JSONArray: 2209 resp = await self._request( 2210 RequestMethod.POST, 2211 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2212 auth=accecss_token, 2213 ) 2214 assert isinstance(resp, list) 2215 return resp
2222 async def fetch_user_clan_invite_setting( 2223 self, 2224 access_token: str, 2225 /, 2226 membership_type: typedefs.IntAnd[enums.MembershipType], 2227 ) -> bool: 2228 resp = await self._request( 2229 RequestMethod.GET, 2230 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2231 auth=access_token, 2232 ) 2233 assert isinstance(resp, bool) 2234 return resp
2236 async def fetch_banned_group_members( 2237 self, access_token: str, group_id: int, /, *, page: int = 1 2238 ) -> typedefs.JSONObject: 2239 resp = await self._request( 2240 RequestMethod.GET, 2241 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2242 auth=access_token, 2243 ) 2244 assert isinstance(resp, dict) 2245 return resp
2247 async def fetch_pending_group_memberships( 2248 self, access_token: str, group_id: int, /, *, current_page: int = 1 2249 ) -> typedefs.JSONObject: 2250 resp = await self._request( 2251 RequestMethod.GET, 2252 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2253 auth=access_token, 2254 ) 2255 assert isinstance(resp, dict) 2256 return resp
2258 async def fetch_invited_group_memberships( 2259 self, access_token: str, group_id: int, /, *, current_page: int = 1 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.GET, 2263 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2264 auth=access_token, 2265 ) 2266 assert isinstance(resp, dict) 2267 return resp
2269 async def invite_member_to_group( 2270 self, 2271 access_token: str, 2272 /, 2273 group_id: int, 2274 membership_id: int, 2275 membership_type: typedefs.IntAnd[enums.MembershipType], 2276 *, 2277 message: undefined.UndefinedOr[str] = undefined.Undefined, 2278 ) -> typedefs.JSONObject: 2279 resp = await self._request( 2280 RequestMethod.POST, 2281 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2282 auth=access_token, 2283 json={"message": str(message)}, 2284 ) 2285 assert isinstance(resp, dict) 2286 return resp
2288 async def cancel_group_member_invite( 2289 self, 2290 access_token: str, 2291 /, 2292 group_id: int, 2293 membership_id: int, 2294 membership_type: typedefs.IntAnd[enums.MembershipType], 2295 ) -> typedefs.JSONObject: 2296 resp = await self._request( 2297 RequestMethod.POST, 2298 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2299 auth=access_token, 2300 ) 2301 assert isinstance(resp, dict) 2302 return resp
2309 async def fetch_historical_stats( 2310 self, 2311 character_id: int, 2312 membership_id: int, 2313 membership_type: typedefs.IntAnd[enums.MembershipType], 2314 day_start: datetime.datetime, 2315 day_end: datetime.datetime, 2316 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2317 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2318 *, 2319 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2320 ) -> typedefs.JSONObject: 2321 2322 end, start = time.parse_date_range(day_end, day_start) 2323 resp = await self._request( 2324 RequestMethod.GET, 2325 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2326 json={ 2327 "dayend": end, 2328 "daystart": start, 2329 "groups": [str(int(group)) for group in groups], 2330 "modes": [str(int(mode)) for mode in modes], 2331 "periodType": int(period_type), 2332 }, 2333 ) 2334 assert isinstance(resp, dict) 2335 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2337 async def fetch_historical_stats_for_account( 2338 self, 2339 membership_id: int, 2340 membership_type: typedefs.IntAnd[enums.MembershipType], 2341 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2342 ) -> typedefs.JSONObject: 2343 resp = await self._request( 2344 RequestMethod.GET, 2345 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2346 json={"groups": [str(int(group)) for group in groups]}, 2347 ) 2348 assert isinstance(resp, dict) 2349 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2351 async def fetch_aggregated_activity_stats( 2352 self, 2353 character_id: int, 2354 membership_id: int, 2355 membership_type: typedefs.IntAnd[enums.MembershipType], 2356 /, 2357 ) -> typedefs.JSONObject: 2358 resp = await self._request( 2359 RequestMethod.GET, 2360 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2361 f"Character/{character_id}/Stats/AggregateActivityStats/", 2362 ) 2363 assert isinstance(resp, dict) 2364 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
244class RESTPool: 245 """Pool of `RESTClient` instances. 246 247 This allows to create multiple instances of `RESTClient`s that can be acquired 248 which share the same config and metadata. 249 250 Example 251 ------- 252 ```py 253 import aiobungie 254 import asyncio 255 256 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 257 258 # Using a context manager to acquire an instance 259 # of the pool and close the connection after finishing. 260 261 async def first() -> str: 262 async with client_pool.acquire() as client: 263 return client.build_oauth2_url() 264 265 async def second() -> None: 266 async with client_pool.acquire() as client: 267 new_tokens = await client.refresh_access_token("token") 268 client.metadata['tokens'] = new_tokens 269 270 # Client instances are independent from first and second. 271 await asyncio.gather(first(), second()) 272 ``` 273 274 Parameters 275 ---------- 276 token : `str` 277 A valid application token from Bungie's developer portal. 278 279 Other Parameters 280 ---------------- 281 max_retries : `int` 282 The max retries number to retry if the request hit a `5xx` status code. 283 max_ratelimit_retries : `int` 284 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 285 client_secret : `typing.Optional[str]` 286 An optional application client secret, 287 This is only needed if you're fetching OAuth2 tokens with this client. 288 client_id : `typing.Optional[int]` 289 An optional application client id, 290 This is only needed if you're fetching OAuth2 tokens with this client. 291 enable_debugging : `bool | str` 292 Whether to enable logging responses or not. 293 294 Logging Levels 295 -------------- 296 * `False`: This will disable logging. 297 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 298 Like the response status, route, taken time and so on. 299 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 300 """ 301 302 __slots__ = ( 303 "_token", 304 "_max_retries", 305 "_client_secret", 306 "_client_id", 307 "_max_rate_limit_retries", 308 "_metadata", 309 "_enable_debug", 310 ) 311 312 # Looks like mypy doesn't like this. 313 if typing.TYPE_CHECKING: 314 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 315 316 def __init__( 317 self, 318 token: str, 319 /, 320 client_secret: typing.Optional[str] = None, 321 client_id: typing.Optional[int] = None, 322 *, 323 max_retries: int = 4, 324 max_rate_limit_retries: int = 3, 325 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 326 ) -> None: 327 self._client_secret = client_secret 328 self._client_id = client_id 329 self._token: str = token 330 self._max_retries = max_retries 331 self._max_rate_limit_retries = max_rate_limit_retries 332 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 333 self._enable_debug = enable_debugging 334 335 @property 336 def client_id(self) -> typing.Optional[int]: 337 return self._client_id 338 339 @property 340 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 341 """Pool's Metadata. This is different from client instance metadata.""" 342 return self._metadata 343 344 @typing.final 345 def acquire(self) -> RESTClient: 346 """Acquires a new `RESTClient` instance from this REST pool. 347 348 Returns 349 ------- 350 `RESTClient` 351 An instance of a REST client. 352 """ 353 instance = RESTClient( 354 self._token, 355 client_secret=self._client_secret, 356 client_id=self._client_id, 357 max_retries=self._max_retries, 358 max_ratelimit_retries=self._max_rate_limit_retries, 359 enable_debugging=self._enable_debug, 360 ) 361 return instance
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same config and metadata.
Example
import aiobungie
import asyncio
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.
async def first() -> str:
async with client_pool.acquire() as client:
return client.build_oauth2_url()
async def second() -> None:
async with client_pool.acquire() as client:
new_tokens = await client.refresh_access_token("token")
client.metadata['tokens'] = new_tokens
# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
316 def __init__( 317 self, 318 token: str, 319 /, 320 client_secret: typing.Optional[str] = None, 321 client_id: typing.Optional[int] = None, 322 *, 323 max_retries: int = 4, 324 max_rate_limit_retries: int = 3, 325 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 326 ) -> None: 327 self._client_secret = client_secret 328 self._client_id = client_id 329 self._token: str = token 330 self._max_retries = max_retries 331 self._max_rate_limit_retries = max_rate_limit_retries 332 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 333 self._enable_debug = enable_debugging
Pool's Metadata. This is different from client instance metadata.
344 @typing.final 345 def acquire(self) -> RESTClient: 346 """Acquires a new `RESTClient` instance from this REST pool. 347 348 Returns 349 ------- 350 `RESTClient` 351 An instance of a REST client. 352 """ 353 instance = RESTClient( 354 self._token, 355 client_secret=self._client_secret, 356 client_id=self._client_id, 357 max_retries=self._max_retries, 358 max_ratelimit_retries=self._max_rate_limit_retries, 359 enable_debugging=self._enable_debug, 360 ) 361 return instance
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
496@typing.final 497class Race(int, Enum): 498 """An Enum for Destiny races.""" 499 500 HUMAN = 0 501 AWOKEN = 1 502 EXO = 2 503 UNKNOWN = 3
An Enum for Destiny races.
148@typing.final 149class Raid(int, Enum): 150 """An Enum for all available raids in Destiny 2.""" 151 152 DSC = 910380154 153 """Deep Stone Crypt""" 154 155 LW = 2122313384 156 """Last Wish""" 157 158 VOG = 3881495763 159 """Normal Valut of Glass""" 160 161 GOS = 3458480158 162 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
200@attrs.define(auto_exc=True) 201class RateLimitedError(HTTPError): 202 """Raised when being hit with ratelimits.""" 203 204 http_status: http.HTTPStatus = attrs.field( 205 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 206 ) 207 """The request response http status.""" 208 209 url: typedefs.StrOrURL 210 """The URL/endpoint caused this error.""" 211 212 body: typing.Any 213 """The response body.""" 214 215 retry_after: float = attrs.field(default=0.0) 216 """The amount of seconds you need to wait before retrying to requests.""" 217 218 message: str = attrs.field(init=False) 219 """A Bungie human readable message describes the cause of the error.""" 220 221 @message.default # type: ignore 222 def _(self) -> str: 223 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 224 225 def __str__(self) -> str: 226 return self.message
Raised when being hit with ratelimits.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
49@typing.final 50class RecordState(enums.Flag): 51 """An enum for records component states.""" 52 53 NONE = 0 54 REDEEMED = 1 55 UNAVAILABLE = 2 56 OBJECTIVE_NOT_COMPLETED = 4 57 OBSCURED = 8 58 INVISIBLE = 16 59 ENTITLEMENT_UNOWNED = 32 60 CAN_EQUIP_TITLE = 64
An enum for records component states.
691@typing.final 692class Relationship(int, Enum): 693 """An enum for bungie friends relationship types.""" 694 695 UNKNOWN = 0 696 FRIEND = 1 697 INCOMING_REQUEST = 2 698 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
225class RequestMethod(str, enums.Enum): 226 """HTTP request methods enum.""" 227 228 GET = "GET" 229 """GET methods.""" 230 POST = "POST" 231 """POST methods.""" 232 PUT = "PUT" 233 """PUT methods.""" 234 PATCH = "PATCH" 235 """PATCH methods.""" 236 DELETE = "DELETE" 237 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
195@attrs.define(auto_exc=True) 196class ResponseError(HTTPException): 197 """Standard HTTP responses exception."""
Standard HTTP responses exception.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
518@typing.final 519class Stat(int, Enum): 520 """An Enum for Destiny 2 character stats.""" 521 522 NONE = 0 523 MOBILITY = 2996146975 524 RESILIENCE = 392767087 525 RECOVERY = 1943323491 526 DISCIPLINE = 1735777505 527 INTELLECT = 144602215 528 STRENGTH = 4244567218 529 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
633@typing.final 634class TierType(int, Enum): 635 """An enum for a Destiny 2 item tier type.""" 636 637 UNKNOWN = 0 638 CURRENCY = 1 639 BASIC = 2 640 COMMON = 3 641 RARE = 4 642 SUPERIOR = 5 643 EXOTIC = 6
An enum for a Destiny 2 item tier type.
743@typing.final 744class TransferStatus(Flag): 745 """An enum for items transfer statuses.""" 746 747 CAN_TRANSFER = 0 748 """The item can be transferred.""" 749 IS_EQUIPPED = 1 750 """You can't transfer since the item is equipped.""" 751 NOT_TRASNFERRABLE = 2 752 """This item can not be transferred.""" 753 COULD_BE_TRANSFERRED = 4 754 """You can trasnfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can trasnfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
245@typing.final 246class Vendor(int, Enum): 247 """An Enum for all available vendors in Destiny 2.""" 248 249 ZAVALA = 69482069 250 XUR = 2190858386 251 BANSHE = 672118013 252 SPIDER = 863940356 253 SHAXX = 3603221665 254 KADI = 529635856 255 """Postmaster exo.""" 256 YUNA = 1796504621 257 """Asia servers only.""" 258 EVERVERSE = 3361454721 259 AMANDA = 460529231 260 """Amanda holiday""" 261 CROW = 3611983588 262 HAWTHORNE = 3347378076 263 ADA1 = 350061650 264 DRIFTER = 248695599 265 IKORA = 1976548992 266 SAINT = 765357505 267 """Saint-14""" 268 ERIS_MORN = 1616085565 269 SHAW_HAWN = 1816541247 270 """COSMODROME Guy""" 271 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
532@typing.final 533class WeaponType(int, Enum): 534 """Enums for The three Destiny Weapon Types""" 535 536 NONE = 0 537 KINETIC = 1498876634 538 ENERGY = 2465295065 539 POWER = 953998645
Enums for The three Destiny Weapon Types
588def into_iter( 589 iterable: collections.Iterable[Item], 590) -> FlatIterator[Item]: 591 """Transform an iterable into an flat iterator. 592 593 Example 594 ------- 595 ```py 596 sequence = [1,2,3] 597 for item in aiobungie.into_iter(sequence).reversed(): 598 print(item) 599 # 3 600 # 2 601 # 1 602 ``` 603 604 Parameters 605 ---------- 606 iterable: `typing.Iterable[Item]` 607 The iterable to convert. 608 609 Raises 610 ------ 611 `StopIteration` 612 If no elements are left in the iterator. 613 """ 614 return FlatIterator(iterable)
Transform an iterable into an flat iterator.
Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
print(item)
# 3
# 2
# 1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
229async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 230 """Generates and raise exceptions on error responses.""" 231 232 # Not a JSON response, raise immediately. 233 234 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 235 # request with a dummy access token. I can't really do anything about this.. 236 if response.content_type != "application/json": 237 return HTTPError( 238 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 239 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 240 ) 241 242 body = await response.json() 243 message: str = body.get("Message", "UNDEFINED_MESSAGE") 244 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 245 message_data: dict[str, str] = body.get("MessageData", {}) 246 throttle_seconds: int = body.get("ThrottleSeconds", 0) 247 error_code: int = body.get("ErrorCode", 0) 248 249 # Standard HTTP status. 250 if response.status == http.HTTPStatus.NOT_FOUND: 251 return NotFound( 252 message=message, 253 error_code=error_code, 254 throttle_seconds=throttle_seconds, 255 url=str(response.real_url), 256 body=body, 257 headers=response.headers, 258 error_status=error_status, 259 message_data=message_data, 260 ) 261 262 elif response.status == http.HTTPStatus.FORBIDDEN: 263 return Forbidden( 264 message=message, 265 error_code=error_code, 266 throttle_seconds=throttle_seconds, 267 url=str(response.real_url), 268 body=body, 269 headers=response.headers, 270 error_status=error_status, 271 message_data=message_data, 272 ) 273 274 elif response.status == http.HTTPStatus.UNAUTHORIZED: 275 return Unauthorized( 276 message=message, 277 error_code=error_code, 278 throttle_seconds=throttle_seconds, 279 url=str(response.real_url), 280 body=body, 281 headers=response.headers, 282 error_status=error_status, 283 message_data=message_data, 284 ) 285 286 elif response.status == http.HTTPStatus.BAD_REQUEST: 287 # Membership needs to be alone. 288 if error_status == "InvalidParameters": 289 return MembershipTypeError( 290 message=message, 291 body=body, 292 headers=response.headers, 293 url=str(response.url), 294 membership_type=message_data["membershipType"], 295 required_membership=message_data["membershipInfo.membershipType"], 296 membership_id=int(message_data["membershipId"]), 297 ) 298 return BadRequest( 299 message=message, 300 body=body, 301 headers=response.headers, 302 url=str(response.url), 303 ) 304 305 status = http.HTTPStatus(response.status) 306 307 if 400 <= status < 500: 308 return ResponseError( 309 message=message, 310 error_code=error_code, 311 throttle_seconds=throttle_seconds, 312 url=str(response.real_url), 313 body=body, 314 headers=response.headers, 315 error_status=error_status, 316 message_data=message_data, 317 http_status=status, 318 ) 319 320 # Need to self handle ~5xx errors 321 elif 500 <= status < 600: 322 # No API key or method requires OAuth2 most likely. 323 if error_status in { 324 "ApiKeyMissingFromRequest", 325 "WebAuthRequired", 326 "ApiInvalidOrExpiredKey", 327 "AuthenticationInvalid", 328 "AuthorizationCodeInvalid", 329 }: 330 return Unauthorized( 331 message=message, 332 error_code=error_code, 333 throttle_seconds=throttle_seconds, 334 url=str(response.real_url), 335 body=body, 336 headers=response.headers, 337 error_status=error_status, 338 message_data=message_data, 339 ) 340 341 # Anything contains not found. 342 elif ( 343 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 344 ): 345 return NotFound( 346 message=message, 347 error_code=error_code, 348 throttle_seconds=throttle_seconds, 349 url=str(response.real_url), 350 body=body, 351 headers=response.headers, 352 error_status=error_status, 353 message_data=message_data, 354 ) 355 356 # Other 5xx errors. 357 else: 358 return InternalServerError( 359 message=message, 360 error_code=error_code, 361 throttle_seconds=throttle_seconds, 362 url=str(response.real_url), 363 body=body, 364 headers=response.headers, 365 error_status=error_status, 366 message_data=message_data, 367 http_status=status, 368 ) 369 # Something else. 370 else: 371 return HTTPException( 372 message=message, 373 error_code=error_code, 374 throttle_seconds=throttle_seconds, 375 url=str(response.real_url), 376 body=body, 377 headers=response.headers, 378 error_status=error_status, 379 message_data=message_data, 380 http_status=status, 381 )
Generates and raise exceptions on error responses.
384def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 385 return ( 386 "{ \n" 387 + "\n".join( # noqa: W503 388 f"{f' {key}'}: {value}" 389 if key not in ("Authorization", "X-API-KEY") 390 else f" {key}: HIDDEN_TOKEN" 391 for key, value in headers.items() 392 ) 393 + "\n}" # noqa: W503 394 )